fix: add optimistic updates for like/favorite actions
- Immediately update store state on user action (no delay) - Increment/decrement count optimistically for instant feedback - Rollback on API error - Use server-returned count for final accuracy - Remove local useState, only use store for state
This commit is contained in:
parent
46b45872c1
commit
458027934a
|
|
@ -17,7 +17,6 @@ export const useTemplateFavorite = (
|
|||
templateId?: string,
|
||||
initialFavorited = false,
|
||||
) => {
|
||||
const [favorited, setFavorited] = useState<boolean>(initialFavorited)
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [error, setError] = useState<ApiError | null>(null)
|
||||
|
||||
|
|
@ -29,6 +28,11 @@ export const useTemplateFavorite = (
|
|||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// 乐观更新:立即更新状态
|
||||
const currentCount = templateSocialStore.getFavoriteCount(templateId) ?? 0
|
||||
templateSocialStore.setFavorited(templateId, true)
|
||||
templateSocialStore.setFavoriteCount(templateId, currentCount + 1)
|
||||
|
||||
const controller = root.get(TemplateSocialController)
|
||||
const params: FavoriteTemplateInput = {
|
||||
templateId,
|
||||
|
|
@ -38,21 +42,21 @@ export const useTemplateFavorite = (
|
|||
async () => await controller.favorite(params),
|
||||
)
|
||||
|
||||
setLoading(false)
|
||||
|
||||
if (error) {
|
||||
// 回滚乐观更新
|
||||
templateSocialStore.setFavorited(templateId, false)
|
||||
templateSocialStore.setFavoriteCount(templateId, currentCount)
|
||||
setError(error)
|
||||
setLoading(false)
|
||||
return { data: null, error }
|
||||
}
|
||||
|
||||
setFavorited(true)
|
||||
|
||||
// 同步更新 store
|
||||
templateSocialStore.setFavorited(templateId, true)
|
||||
// 使用服务器返回的准确数量
|
||||
if (data?.favoriteCount !== undefined) {
|
||||
templateSocialStore.setFavoriteCount(templateId, data.favoriteCount)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
return { data, error: null }
|
||||
}, [templateId])
|
||||
|
||||
|
|
@ -64,6 +68,11 @@ export const useTemplateFavorite = (
|
|||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// 乐观更新:立即更新状态
|
||||
const currentCount = templateSocialStore.getFavoriteCount(templateId) ?? 0
|
||||
templateSocialStore.setFavorited(templateId, false)
|
||||
templateSocialStore.setFavoriteCount(templateId, Math.max(0, currentCount - 1))
|
||||
|
||||
const controller = root.get(TemplateSocialController)
|
||||
const params: UnfavoriteTemplateInput = {
|
||||
templateId,
|
||||
|
|
@ -73,21 +82,21 @@ export const useTemplateFavorite = (
|
|||
async () => await controller.unfavorite(params),
|
||||
)
|
||||
|
||||
setLoading(false)
|
||||
|
||||
if (error) {
|
||||
// 回滚乐观更新
|
||||
templateSocialStore.setFavorited(templateId, true)
|
||||
templateSocialStore.setFavoriteCount(templateId, currentCount)
|
||||
setError(error)
|
||||
setLoading(false)
|
||||
return { data: null, error }
|
||||
}
|
||||
|
||||
setFavorited(false)
|
||||
|
||||
// 同步更新 store
|
||||
templateSocialStore.setFavorited(templateId, false)
|
||||
// 使用服务器返回的准确数量
|
||||
if (data?.favoriteCount !== undefined) {
|
||||
templateSocialStore.setFavoriteCount(templateId, data.favoriteCount)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
return { data, error: null }
|
||||
}, [templateId])
|
||||
|
||||
|
|
@ -108,19 +117,21 @@ export const useTemplateFavorite = (
|
|||
async () => await controller.checkFavorited(params),
|
||||
)
|
||||
|
||||
setLoading(false)
|
||||
|
||||
if (error) {
|
||||
setError(error)
|
||||
setLoading(false)
|
||||
return { data: null, error }
|
||||
}
|
||||
|
||||
setFavorited(data.favorited)
|
||||
setLoading(false)
|
||||
if (data?.favorited !== undefined) {
|
||||
templateSocialStore.setFavorited(templateId, data.favorited)
|
||||
}
|
||||
|
||||
return { data, error: null }
|
||||
}, [templateId])
|
||||
|
||||
return {
|
||||
favorited,
|
||||
loading,
|
||||
error,
|
||||
favorite,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { handleError } from './use-error'
|
|||
import { templateSocialStore } from '@/stores/templateSocialStore'
|
||||
|
||||
export const useTemplateLike = (templateId?: string) => {
|
||||
const [liked, setLiked] = useState<boolean>(false)
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [error, setError] = useState<ApiError | null>(null)
|
||||
|
||||
|
|
@ -19,6 +18,11 @@ export const useTemplateLike = (templateId?: string) => {
|
|||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// 乐观更新:立即更新状态
|
||||
const currentCount = templateSocialStore.getLikeCount(templateId) ?? 0
|
||||
templateSocialStore.setLiked(templateId, true)
|
||||
templateSocialStore.setLikeCount(templateId, currentCount + 1)
|
||||
|
||||
const social = root.get(TemplateSocialController)
|
||||
const { data, error } = await handleError(
|
||||
async () => await social.like({ templateId })
|
||||
|
|
@ -27,14 +31,14 @@ export const useTemplateLike = (templateId?: string) => {
|
|||
setLoading(false)
|
||||
|
||||
if (error) {
|
||||
// 回滚乐观更新
|
||||
templateSocialStore.setLiked(templateId, false)
|
||||
templateSocialStore.setLikeCount(templateId, currentCount)
|
||||
setError(error)
|
||||
return { error }
|
||||
}
|
||||
|
||||
setLiked(true)
|
||||
|
||||
// 同步更新 store
|
||||
templateSocialStore.setLiked(templateId, true)
|
||||
// 使用服务器返回的准确数量
|
||||
if (data?.likeCount !== undefined) {
|
||||
templateSocialStore.setLikeCount(templateId, data.likeCount)
|
||||
}
|
||||
|
|
@ -50,6 +54,11 @@ export const useTemplateLike = (templateId?: string) => {
|
|||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// 乐观更新:立即更新状态
|
||||
const currentCount = templateSocialStore.getLikeCount(templateId) ?? 0
|
||||
templateSocialStore.setLiked(templateId, false)
|
||||
templateSocialStore.setLikeCount(templateId, Math.max(0, currentCount - 1))
|
||||
|
||||
const social = root.get(TemplateSocialController)
|
||||
const { data, error } = await handleError(
|
||||
async () => await social.unlike({ templateId })
|
||||
|
|
@ -58,14 +67,14 @@ export const useTemplateLike = (templateId?: string) => {
|
|||
setLoading(false)
|
||||
|
||||
if (error) {
|
||||
// 回滚乐观更新
|
||||
templateSocialStore.setLiked(templateId, true)
|
||||
templateSocialStore.setLikeCount(templateId, currentCount)
|
||||
setError(error)
|
||||
return { error }
|
||||
}
|
||||
|
||||
setLiked(false)
|
||||
|
||||
// 同步更新 store
|
||||
templateSocialStore.setLiked(templateId, false)
|
||||
// 使用服务器返回的准确数量
|
||||
if (data?.likeCount !== undefined) {
|
||||
templateSocialStore.setLikeCount(templateId, data.likeCount)
|
||||
}
|
||||
|
|
@ -93,12 +102,13 @@ export const useTemplateLike = (templateId?: string) => {
|
|||
return { error }
|
||||
}
|
||||
|
||||
setLiked(data?.liked || false)
|
||||
if (data?.liked !== undefined) {
|
||||
templateSocialStore.setLiked(templateId, data.liked)
|
||||
}
|
||||
return {}
|
||||
}, [templateId])
|
||||
|
||||
return {
|
||||
liked,
|
||||
loading,
|
||||
error,
|
||||
like,
|
||||
|
|
|
|||
Loading…
Reference in New Issue