Deepdive into Tanstack/React Query - 2.3 QueryObserver 结果计算与通知
2.3 QueryObserver 结果计算与通知
在上一节中,我们了解了 QueryObserver 的基本概念和订阅机制。本节将深入探讨 QueryObserver 如何根据 Query 状态计算出最终的结果对象 (QueryObserverResult),以及如何高效地通知订阅者。
2.3.1 createResult 方法深度解析
createResult 是 QueryObserver 中最核心的方法之一,它负责将 Query 的原始状态转换为 UI 可直接使用的结果对象。
源码解析: createResult 方法首先获取并保存之前的查询、选项和结果的引用,用于后续的比较和优化。然后复制当前查询状态作为基础状态 newState。
结果对象的完整结构
最终返回的结果对象包含丰富的状态信息:
2.3.2 乐观结果 (_optimisticResults) 处理
乐观结果是 QueryObserver 的一个重要特性,它允许在实际数据获取之前,根据当前状态预测并返回一个"乐观"的结果。这在 React 等框架中用于提供更流畅的用户体验。
源码解析:
_optimisticResults是一个内部选项,通常由框架适配器(如@tanstack/react-query)设置- 当启用乐观结果时,如果判断出即将触发数据获取,会预先将
fetchStatus设置为'fetching' 'isRestoring'是一个特殊值,用于 hydration 或持久化恢复场景,此时强制fetchStatus为'idle'
getOptimisticResult 方法
此方法被框架适配器(如 React 的 useQuery)调用,用于在渲染期间获取乐观结果,同时可能更新观察者的内部状态以保持一致性。
2.3.3 select 数据转换与缓存
select 选项允许用户对查询返回的数据进行转换,只获取所需的部分数据。QueryObserver 实现了对 select 结果的智能缓存,避免不必要的重复计算。
源码解析:
- 缓存策略: 通过比较原始数据引用 (
data === prevResultState?.data) 和 select 函数引用 (options.select=== this.#selectFn) 来判断是否可以复用缓存 - 结构共享:
replaceData函数实现了深度结构共享,如果新旧数据结构相似,会尽量复用对象引用,减少不必要的重渲染 - 错误处理: select 函数中的错误会被捕获并存储在
#selectError中,随后会影响最终结果的status和error
select 错误处理
2.3.4 placeholderData 机制
placeholderData 允许在数据加载期间显示占位数据,提升用户体验。TanStack Query 对 placeholderData 的处理包含了智能的缓存和上下文传递机制。
源码解析:
- 触发条件: 只有当
placeholderData配置存在、当前无数据 (data === undefined) 且状态为pending时才会使用 - 函数形式:
placeholderData可以是一个函数,接收上一次有数据的查询的数据和实例作为参数,这对于分页或详情页场景非常有用 #lastQueryWithDefinedData: 观察者内部维护了一个对"最后一次有数据的查询"的引用,用于在 queryKey 变化时传递上下文- 状态转换: 使用 placeholder 数据时,
status会被设为'success',同时isPlaceholderData标记为true
2.3.5 #notify 通知流程与 notifyOnChangeProps 优化
QueryObserver 通过 #notify 方法将结果变化通知给所有订阅者。为了优化性能,TanStack Query 实现了基于属性追踪的精细化通知机制。
属性追踪机制
源码解析: trackResult 返回一个 Proxy 包装的结果对象。当 UI 组件访问结果的某个属性时,该属性会被自动添加到 #trackedProps 集合中。这样,QueryObserver 就知道哪些属性是组件真正关心的。
updateResult 与条件通知
#notify 方法
源码解析:
notifyOnChangeProps选项允许用户显式指定关心的属性列表- 自动追踪: 如果未配置
notifyOnChangeProps,则使用#trackedProps(通过 Proxy 自动收集) - 批处理:
notifyManager.batch()确保多个通知被合并处理,减少重渲染次数 - 双层通知: 先通知组件监听器,再通知
QueryCache的全局监听器(用于 DevTools 等)
2.3.6 总结
QueryObserver 的结果计算与通知机制体现了 TanStack Query 的精巧设计:
- 乐观结果: 提前预测即将发生的状态变化,提供更流畅的 UI 体验
- select 缓存: 智能复用转换结果,避免不必要的计算
- placeholderData: 支持函数形式,可访问上一次查询的数据
- 精细化通知: 基于属性追踪,只在关心的属性变化时才通知组件
这些机制共同确保了 TanStack Query 在提供强大功能的同时,保持了优秀的性能表现。