FavouriteGameButton组件问题:图标未同步Mutation结果
问题:收藏按钮图标无法随Mutation结果即时更新
当用户点击FavouriteGameButton组件收藏/取消收藏游戏时,图标不能根据updateFavouriteGameMutation的结果立刻切换状态,求排查思路和解决方案。
相关组件代码
GamePageTop.tsx
type Props = { gameId: string; }; export const GamePageTop: FC<Props> = ({ gameId }) => { const { user } = useUser(); if (!user) { return null; } const [{ data: userData }] = useUserQuery({ variables: { userId: user.id }, }); const favouriteGame = userData?.user?.favouriteGame.map((it) => it.game.id); return ( <FavouriteGameButton gameId={gameId} isFavourite={favouriteGame?.includes(gameId) || false} /> ); };
FavouriteGameButton.tsx
type Props = { gameId: string; isFavourite: boolean; }; export const FavouriteGameButton: FC<Props> = ({ gameId, isFavourite }) => { const { user } = useUser(); const [, updateFavouriteGame] = useUpdateFavouriteGameMutation(); if (!user) { return null; } const handleUpdateFavouriteGame = async () => { await updateFavouriteGame({ userId: user.id, gameId: gameId, action: isFavourite ? "remove" : "add", }); }; return ( <ButtonComponent size="normal" hovercolor="transparent" backgroundcolor="transparent" padding="0px" onClick={() => { handleUpdateFavouriteGame(); }} > {isFavourite ? ( <Icon icon="starFill" size="M" color={Colors.TagText} /> ) : ( <Icon icon="starOutline" size="M" color={Colors.TagText} /> )} </ButtonComponent> ); };
排查思路与解决方案
1. 手动更新Apollo缓存(精准控制)
Mutation执行完成后,直接修改useUserQuery对应的缓存数据,触发GamePageTop重新渲染:
// 在FavouriteGameButton中导入useApolloClient import { useApolloClient } from '@apollo/client'; export const FavouriteGameButton: FC<Props> = ({ gameId, isFavourite }) => { const { user } = useUser(); const client = useApolloClient(); const [, updateFavouriteGame] = useUpdateFavouriteGameMutation(); if (!user) { return null; } const handleUpdateFavouriteGame = async () => { await updateFavouriteGame({ userId: user.id, gameId: gameId, action: isFavourite ? "remove" : "add", }); // 更新缓存中的用户收藏列表 client.cache.modify({ id: client.cache.identify({ __typename: 'User', id: user.id }), fields: { favouriteGame(existingFavourites = []) { if (isFavourite) { // 取消收藏:移除对应游戏 return existingFavourites.filter(fav => fav.game.id !== gameId); } else { // 添加收藏:新增项(需与后端返回的类型结构一致) return [...existingFavourites, { __typename: 'FavouriteGame', game: { __typename: 'Game', id: gameId } }]; } } } }); }; // 其余代码不变 };
2. 利用Mutation的refetchQueries强制刷新
调用Mutation时指定refetchQueries,重新获取用户数据,让GamePageTop拿到最新的收藏状态:
const handleUpdateFavouriteGame = async () => { await updateFavouriteGame({ userId: user.id, gameId: gameId, action: isFavourite ? "remove" : "add", // 替换成你的UserQuery文档 refetchQueries: [{ query: UserDocument, variables: { userId: user.id } }] }); };
3. 本地状态优先提升体验
先切换本地状态更新图标,再同步后端,避免等待网络请求带来的延迟,请求失败时回滚状态:
import { useState } from 'react'; export const FavouriteGameButton: FC<Props> = ({ gameId, isFavourite: initialIsFavourite }) => { const { user } = useUser(); const [isFavourite, setIsFavourite] = useState(initialIsFavourite); const [, updateFavouriteGame] = useUpdateFavouriteGameMutation(); if (!user) { return null; } const handleUpdateFavouriteGame = async () => { // 先切换本地状态 const newState = !isFavourite; setIsFavourite(newState); try { await updateFavouriteGame({ userId: user.id, gameId: gameId, action: isFavourite ? "remove" : "add", }); } catch (error) { // 请求失败,回滚状态 setIsFavourite(isFavourite); // 可添加错误提示逻辑 console.error('更新收藏失败:', error); } }; return ( <ButtonComponent size="normal" hovercolor="transparent" backgroundcolor="transparent" padding="0px" onClick={handleUpdateFavouriteGame} > {isFavourite ? ( <Icon icon="starFill" size="M" color={Colors.TagText} /> ) : ( <Icon icon="starOutline" size="M" color={Colors.TagText} /> )} </ButtonComponent> ); };
4. 检查缓存策略与返回值
- 确认后端的updateFavouriteGame接口是否返回更新后的用户收藏数据,若返回正确的类型和ID,Apollo Client可能自动更新缓存
- 检查useUserQuery的
fetchPolicy,若设置为cache-only,则不会主动拉取新数据,可调整为cache-first(默认)或network-only
内容的提问来源于stack exchange,提问作者Mei Kei
相关产品推荐
相关产品推荐

