You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:59:52