Deepdive into Tanstack/React Query - 2.5 QueryCache 缓存管理
2.5 QueryCache 缓存管理
QueryCache 是 TanStack Query 中管理所有 Query 实例的中央存储。它负责查询的创建、存储、查找、移除以及全局事件的分发。本节将深入分析 QueryCache 的实现细节。
2.5.1 缓存结构与 #queries Map
QueryCache 继承自 Subscribable,具备发布-订阅能力,可以向外部(如 DevTools)广播缓存事件。
QueryStore 接口
源码解析: #queries 使用 Map 实现,以 queryHash 作为键,Query 实例作为值。这种设计提供了 O(1) 的查找性能。
QueryCacheConfig 配置
这些全局回调允许开发者在缓存级别监听所有查询的生命周期事件,常用于日志记录、错误追踪等场景。
2.5.2 build 方法:查找或创建 Query
build 是 QueryCache 最核心的方法,它实现了查找或创建的语义:如果缓存中已存在匹配的 Query,则返回它;否则创建新的 Query 并添加到缓存。
源码解析:
- queryHash 计算: 如果
options中没有提供queryHash,则通过hashQueryKeyByOptions函数计算 - 缓存查找: 使用
this.get(queryHash)尝试获取已存在的 Query - 创建新 Query: 如果不存在,创建新的 Query 实例并添加到缓存
- state 参数: 可选的初始状态,主要用于 SSR hydration 场景
2.5.3 queryHash 与 queryKey 的关系
queryKey 和 queryHash 是 TanStack Query 中两个密切相关但不同的概念:
| 概念 | 类型 | 用途 |
| queryKey | unknown[] | 用户定义的查询标识,支持复杂嵌套结构 |
| queryHash | string | queryKey 的字符串哈希,用作 Map 的键 |
哈希计算
源码解析:
- 自定义哈希: 可通过
queryKeyHashFn选项提供自定义哈希函数 - 对象键排序: 默认哈希函数会对对象的键进行排序,确保
{ a: 1, b: 2 }和{ b: 2, a: 1 }生成相同的哈希 - JSON 序列化: 使用
JSON.stringify将 queryKey 转换为字符串
示例
2.5.4 添加、获取、移除操作
添加 Query
获取 Query
移除 Query
查找 Query
2.5.5 事件系统 (QueryCacheListener)
QueryCache 通过事件系统向外部广播各种缓存状态变化,这对于 DevTools、日志记录等场景非常有用。
事件类型
通知机制
订阅示例(DevTools 场景)
2.5.6 onFocus/onOnline 触发重新获取
QueryCache 提供了响应窗口聚焦和网络恢复事件的方法,用于实现自动重新获取功能。
Query 中的处理
完整流程
Loading diagram...
2.5.7 总结
QueryCache 是 TanStack Query 的核心基础设施,其设计体现了以下关键思想:
- 高效查找: 使用 Map + queryHash 实现 O(1) 查找性能
- 键规范化: 通过排序和 JSON 序列化确保语义相同的 queryKey 生成相同的 hash
- 事件驱动: 完善的事件系统支持 DevTools 和外部监听
- 批量处理: 使用
notifyManager.batch()优化通知性能 - 全局回调: 提供
onError/onSuccess/onSettled钩子用于全局监听
Loading diagram...
通过 QueryCache,TanStack Query 实现了:
- 查询去重: 相同 queryKey 的请求共享同一个 Query 实例
- 全局状态管理: 所有查询状态集中管理
- 自动重新获取: 响应窗口聚焦和网络恢复事件
- 开发者工具支持: 通过事件系统提供完整的可观测性