Deepdive into Tanstack/React Query - 3. 缓存策略与生命周期
本章深入探讨 Tanstack Query 的缓存策略与生命周期管理机制。理解这些概念对于优化应用性能、减少不必要的网络请求至关重要。
3.1 gcTime 与垃圾回收
gcTime(Garbage Collection Time)控制着 Query 在没有观察者时能在缓存中存活多久。这个机制的核心实现位于 Removable 基类中。
Removable 基类解析
Removable 是一个抽象基类,为 Query 和 Mutation 提供了统一的垃圾回收能力:
isValidTimeout 用于判断超时值是否有效——必须是有限数字且大于等于 0。当 gcTime 为 Infinity 时,Query 将永远不会被垃圾回收。scheduleGc 与 clearGcTimeout
垃圾回收的调度时机主要有两个:
- 观察者移除时:当最后一个观察者从 Query 上移除时
- 获取完成时:当没有观察者的 Query 完成数据获取时
clearGcTimeout 的调用时机则是在有新观察者订阅时:
观察者数量与 GC 调度的关系
这种设计形成了一个优雅的生命周期模式:
gcTime 的默认值在客户端是 5 分钟,在服务端是 Infinity。服务端设置为无限是为了防止 SSR 期间缓存被意外清理。3.2 staleTime 与数据新鲜度
staleTime 决定了数据被认为是"新鲜"的时长。在这个时间内,Query 不会自动重新获取数据。
isStale 判断逻辑
Query 类提供了 isStale 方法来判断数据是否过期:
在 QueryObserver 中,isStale 的计算更加细致:
#updateStaleTimeout 实现
QueryObserver 使用私有方法 #updateStaleTimeout 来管理数据新鲜度的定时器:
timeUntilStale 是一个辅助函数,计算距离数据变为 stale 还有多长时间:
staleTime: 'static' 特殊值
从 v5 版本开始,staleTime 支持一个特殊的字符串值 'static':
'static' 等价于 staleTime: Infinity,但语义更清晰,表示这是一个静态数据,在应用的整个生命周期内都不需要重新获取。与 dataUpdatedAt 的配合
dataUpdatedAt 记录了数据最后更新的时间戳,是判断数据新鲜度的关键:
数据新鲜度的判断公式:
时间线示意:
3.3 缓存数据操作
Tanstack Query 提供了一系列 API 来操作缓存数据,这些 API 都在 QueryClient 上暴露。
setQueryData 与乐观更新
setQueryData 允许直接修改缓存中的数据,是实现乐观更新的核心 API:
Query.setData 的实现:
invalidateQueries 标记失效
invalidateQueries 将匹配的 Query 标记为失效(stale),并可选择触发重新获取:
Query.invalidate 的实现非常简单:
refetchType 参数控制失效后的行为:
| 值 | 行为 |
'active' | 只重新获取当前有观察者的 Query(默认) |
'inactive' | 只重新获取没有观察者的 Query |
'all' | 重新获取所有匹配的 Query |
'none' | 只标记失效,不触发重新获取 |
resetQueries 与 removeQueries
resetQueries 将 Query 重置到初始状态:
Query.reset 的实现:
removeQueries 直接从缓存中移除 Query:
| 操作 | reset | remove |
| 缓存数据 | 清除 | 清除 |
| Query 实例 | 保留 | 移除 |
| 后续访问 | 触发新请求 | 触发新请求 |
| 适用场景 | 用户登出后清空用户数据 | 完全清理不再需要的数据 |
cancelQueries 取消进行中请求
cancelQueries 用于取消正在进行的请求,常用于乐观更新前避免竞态条件:
Query.cancel 的实现:
取消机制依赖于 AbortController:
queryFn 中始终使用传入的 signal 来支持请求取消:小结
本章详细解析了 Tanstack Query 的缓存策略与生命周期管理:
- gcTime 机制:通过
Removable基类实现,当 Query 没有观察者时开始倒计时,超时后从缓存移除 - staleTime 机制:控制数据的新鲜度,在 staleTime 内不会自动重新获取数据
- 缓存操作 API:
setQueryData:直接设置缓存数据,实现乐观更新invalidateQueries:标记失效并可选重新获取resetQueries:重置到初始状态removeQueries:从缓存中移除cancelQueries:取消进行中的请求
理解这些机制后,你就能更好地控制数据的缓存行为,优化应用性能,实现流畅的用户体验。
下一章将探讨 重试与网络管理,包括 Retryer 重试机制、NetworkMode 网络模式以及 FocusManager 与 OnlineManager 的实现。