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

Apollo Client组件重渲染时useQuery未触发执行问题咨询

问题原因
  • useQuery默认的fetchPolicy为cache-first(缓存优先),只要查询参数没有发生变化、缓存中存在对应数据,就不会主动发起新的网络请求。你通过rerender状态触发的组件重渲染没有改变useQuery的入参,因此不会触发重新查询。
  • 你在缓存配置中自定义了Query.movies字段的read方法,直接返回movieVar的值,这会导致所有对movies字段的读取都优先走你自定义的逻辑,接口返回的原始数据会被覆盖,即便发起请求也不会更新data的结果。
  • 你的movieVar类型配置错误:当前movieVar定义为单个IMovie对象,但接口返回的movies是数组,类型不匹配会导致后续逻辑异常。
  • 自定义的useEffect逻辑无效:你在useEffect中修改的是局部变量movies,组件重渲染后该变量会被重置为data?.movies,追加操作不会生效;同时useReactiveVar是Hook,不能直接放在依赖数组中调用,需要在组件顶层调用后将返回值放入依赖。

修复方案

你不需要手动写useEffect和触发重渲染的状态,Apollo会自动感知响应式变量的变化更新查询结果,按以下步骤修改即可:

步骤1:调整缓存配置

修改movies字段的read方法,合并接口返回的原有列表和响应式变量存储的新增电影,避免覆盖原始数据:

// cache.tsx
import {InMemoryCache, ReactiveVar, makeVar} from '@apollo/client';
import {IMovie} from './movieseat';

export const movieVar: ReactiveVar<IMovie> = makeVar<IMovie>({id: 0, original_title: '', backdrop_path: '', poster_path: '', release_date: ''});

export const cache: InMemoryCache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        movies: {
          read(existingMovies: IMovie[] = []) {
            const newMovie = movieVar();
            // 过滤空对象、避免重复添加
            if (newMovie.id && !existingMovies.some(movie => movie.id === newMovie.id)) {
              return [...existingMovies, newMovie];
            }
            return existingMovies;
          },
        },
      },
    },
  },
});

步骤2:简化MovieOverview组件

删除冗余的状态和副作用逻辑,直接使用useQuery返回的数据即可,Apollo会在movieVar更新时自动更新查询结果、触发组件重渲染:

// MovieOverview.tsx
const MovieOverview = () => {
  const {loading, error, data} = useQuery(resolvers.queries.ReturnAllMovies);

  if (loading) return <p>loading</p>;
  if (error) return <p>Error! ${error.message}</p>;

  return (
    <div>
      {data?.movies?.length || 0}
    </div>
  );
};

步骤3(可选):新增后同步服务端数据

如果你需要在添加电影后拉取服务端最新的全量列表,可以在useMutation中添加refetchQueries配置,指定新增完成后重新执行ReturnAllMovies查询:

// addMovie.tsx
const [addMovieRes] = useMutation(resolvers.mutations.AddMovie, {
  //  mutation执行成功后自动重新拉取电影列表
  refetchQueries: [resolvers.queries.ReturnAllMovies],
});

addMovieRes({variables: {
  original_title: movie.original_title,
  tmdb_id: movie.id,
  poster_path: movie.poster_path,
}});

movieVar(movie);

内容的提问来源于stack exchange,提问作者Peter Boomsma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:36:03