You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Query与Apollo Client如何保障数据更新?缓存策略与后台请求机制解析

React Query 与 Apollo Client:缓存判断逻辑、后台请求与资源优化解析

嘿,这个问题问得特别戳中痛点——很多文档只会告诉你“这俩库会缓存数据、自动更新”,但底层的决策逻辑和细节往往一笔带过。我来给你拆解清楚每个疑问:

一、核心判断逻辑:何时用缓存,何时发请求?

这两个库的缓存机制本质不同,导致判断逻辑差异很大:

React Query:基于「查询状态」的决策

React Query把缓存数据分成两种状态:Fresh(新鲜)Stale(过期),核心判断依据是queryKey(唯一标识查询的键)和你配置的staleTime(新鲜时长):

  • 当发起查询时,先通过queryKey匹配缓存条目
    • 如果缓存数据还在staleTime有效期内(处于Fresh状态):直接返回缓存,完全不发网络请求
    • 如果缓存数据超过staleTime(处于Stale状态):先立刻返回缓存数据给组件渲染,同时后台悄悄发起请求更新缓存,请求完成后再把最新数据同步给组件
  • 额外触发条件:你也可以手动通过refetch()invalidateQueries()强制刷新,或者开启refetchOnWindowFocus(窗口聚焦时刷新)、refetchOnReconnect(网络重连时刷新)等规则,这些场景下也会发请求

Apollo Client:基于「缓存策略」与「归一化缓存」的决策

Apollo是为GraphQL设计的,它的缓存是归一化对象缓存(把返回的GraphQL数据拆成单个对象,用__typename+id/_id作为唯一键存储),判断逻辑主要看你指定的fetchPolicy(获取策略):

  • 默认策略cache-first:先在归一化缓存里找匹配的对象,找到就直接返回,完全不发网络请求;找不到才发请求并把结果存入缓存
  • cache-and-network:和React Query的Stale状态逻辑类似——先返回缓存,同时发请求更新缓存
  • network-only:完全跳过缓存,每次都发请求
  • no-cache:每次发请求,请求结果不存入缓存
  • 另外,用watchQuery时,Apollo会监听缓存中对应对象的变化,一旦本地缓存被修改(比如mutation后的手动更新),会自动通知组件刷新,但这是客户端缓存监听,没有网络请求

二、后台请求为什么在浏览器网络面板看不到?

你说的“看不到”通常有三种原因:

  1. 根本没发请求
    • React Query中如果缓存还在staleTime的新鲜期,不会发起任何请求,网络面板自然看不到
    • Apollo用cache-first策略且缓存命中时,也不会发请求
  2. 没捕捉到请求时机
    • React Query的后台刷新请求是在组件拿到缓存数据之后发起的,可能你刚打开网络面板时缓存已经返回,请求还在pending或者已经完成;可以试试清空缓存后重新加载,或者开启Preserve log再操作
    • 另外,React Query的refetchOnWindowFocus触发的请求,只有当你从其他窗口切回来时才会发,如果你一直停留在当前页面,也看不到这个请求
  3. 是本地缓存更新而非网络请求
    比如执行mutation后,用React Query的setQueryData或者Apollo的update函数直接修改客户端缓存,这种操作完全在本地进行,没有网络请求,所以网络面板看不到

三、React Query的后台检查会造成资源浪费吗?

这个顾虑很合理,但React Query已经做了很多优化来避免不必要的请求:

  • 可配置的新鲜时长:你可以把staleTime设置成任意时长(比如1小时、1天),只要数据在新鲜期内,就不会发任何后台请求
  • 按需触发刷新:默认只有当组件处于活跃挂载状态、且缓存过期时,才会发起后台请求;如果组件已经卸载,不会触发刷新
  • 可关闭自动刷新规则refetchOnWindowFocusrefetchOnReconnect这些默认开启的规则,你可以根据业务需求关闭,避免不必要的请求
  • 缓存垃圾回收:React Query会自动清理长时间未被使用的缓存(默认是5分钟),不会一直占用内存
  • 请求防抖/节流:对于频繁触发的查询(比如搜索框输入),你可以配置queryFn的防抖逻辑,避免短时间内多发请求

简单说:React Query的后台请求不是“持续无差别发送”,而是基于缓存状态和组件状态的条件触发,你完全可以通过配置来平衡数据新鲜度和资源消耗。

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

火山引擎 最新活动