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

使用Apollo Client的useQuery获取数据后React组件未重渲染问题

问题根因

  • Apollo Client默认开启了缓存结构化共享策略:当接口返回的data数据与本地缓存中已有的对应数据完全一致时,会复用原有对象的内存引用。而React的useEffect依赖对比是浅比较,检测到data引用没有变化,就不会触发对应回调执行,你的status也就不会更新。
  • 冗余状态引入的额外问题:你额外定义的status状态和对应useEffect完全是不必要的,多了一层状态转换反而会引入时序差:当loading结束后data已经存在,但useEffect的回调是在本次渲染提交之后才执行,此时render逻辑里拿到的status还是旧值,就会出现已经拿到data却还是走了重定向逻辑的问题。

解决方案

最优方案:移除冗余状态

直接在渲染逻辑中用useQuery返回的data做判断,不需要额外维护status:

export default function PrivateRoute({
  exact,
  path,
  component: Component,
  ...rest
}: Props): ReactElement {
  const { data, error, loading } = useQuery(GET_CURRENT_USER);

  if (error) console.log(error);
  if (loading) return <Spinner></Spinner>;

  return (
    <Route
      {...rest}
      render={(props) =>
        data?.id ? (
          <>
            <Navbar></Navbar>
            <Component {...props} />
          </>
        ) : (
          <Redirect
            to={{ pathname: "/login", state: { from: props.location } }}
          />
        )
      }
    />
  );
}

如果你确实需要监听data变化做额外操作

如果后续有其他逻辑需要在data更新时执行,不要把整个data对象放到依赖数组里,换成你实际用到的基本类型字段即可:

// 监听具体的id字段,基本类型值变化就能触发useEffect
useEffect(() => {
  data?.id && setStatus(true);
}, [data?.id]);

如果需要强制让useQuery在每次请求完成后都返回新的data引用,可以给useQuery添加配置:

const { data, error, loading } = useQuery(GET_CURRENT_USER, {
  notifyOnNetworkStatusChange: true
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 21:00:03