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后的手动更新),会自动通知组件刷新,但这是客户端缓存监听,没有网络请求
二、后台请求为什么在浏览器网络面板看不到?
你说的“看不到”通常有三种原因:
- 根本没发请求:
- React Query中如果缓存还在
staleTime的新鲜期,不会发起任何请求,网络面板自然看不到 - Apollo用
cache-first策略且缓存命中时,也不会发请求
- React Query中如果缓存还在
- 没捕捉到请求时机:
- React Query的后台刷新请求是在组件拿到缓存数据之后发起的,可能你刚打开网络面板时缓存已经返回,请求还在pending或者已经完成;可以试试清空缓存后重新加载,或者开启
Preserve log再操作 - 另外,React Query的
refetchOnWindowFocus触发的请求,只有当你从其他窗口切回来时才会发,如果你一直停留在当前页面,也看不到这个请求
- React Query的后台刷新请求是在组件拿到缓存数据之后发起的,可能你刚打开网络面板时缓存已经返回,请求还在pending或者已经完成;可以试试清空缓存后重新加载,或者开启
- 是本地缓存更新而非网络请求:
比如执行mutation后,用React Query的setQueryData或者Apollo的update函数直接修改客户端缓存,这种操作完全在本地进行,没有网络请求,所以网络面板看不到
三、React Query的后台检查会造成资源浪费吗?
这个顾虑很合理,但React Query已经做了很多优化来避免不必要的请求:
- 可配置的新鲜时长:你可以把
staleTime设置成任意时长(比如1小时、1天),只要数据在新鲜期内,就不会发任何后台请求 - 按需触发刷新:默认只有当组件处于活跃挂载状态、且缓存过期时,才会发起后台请求;如果组件已经卸载,不会触发刷新
- 可关闭自动刷新规则:
refetchOnWindowFocus、refetchOnReconnect这些默认开启的规则,你可以根据业务需求关闭,避免不必要的请求 - 缓存垃圾回收:React Query会自动清理长时间未被使用的缓存(默认是5分钟),不会一直占用内存
- 请求防抖/节流:对于频繁触发的查询(比如搜索框输入),你可以配置
queryFn的防抖逻辑,避免短时间内多发请求
简单说:React Query的后台请求不是“持续无差别发送”,而是基于缓存状态和组件状态的条件触发,你完全可以通过配置来平衡数据新鲜度和资源消耗。
内容的提问来源于stack exchange,提问作者newbie




