Important Defaults
TanStack Query 有一些开箱即用的默认配置,具体如下:
1. 通过useQuery
或useInfiniteQuery
的查询实例获取的数据,不再默认是缓存数据。(每次都重新发起请求获取数据)
若要修改,可以使用
staleTime
选项配置全局查询或单个查询。配置更长的staleTime
意味着查询不会经常重新获取数据。
2. 在以下几种情况下,旧的查询会在后台重新获取:
- 重新挂载查询实例
- 浏览器窗口被重新聚焦(focus)
- 网络重新连接
- 该查询配置了一个重新获取的间隔时间(refetch interval)
若要修改,可以使用
refetchOnMount
,refetchOnWindowFocus
,refetchOnReconnect
和refetchInterval
。
3. 没有活动的useQuery
、useInfiniteQuery
或 query observers 的查询结果,会被标记为“非活动”,并保留在缓存中,以防以后再次使用它们。
4. 默认情况下,“非活动”查询在5分钟后被垃圾回收。
若要修改,可以将查询的默认
gcTime
更改为1000 * 60 * 5毫秒以外的值。
5. 失败的查询会被静默地重试3次,在捕获并向UI显示错误之前会有指数级的回退延迟。
若要修改,可以将查询的
retry
和retryDelay
选项更改为3以外的值和默认指数回退函数
6. 默认情况下,查询结果在结构上是共享的,以检测数据是否实际发生了变化,若没有,则数据引用保持不变,以更好地帮助实现关于useMemo
和useCallback
的值稳定。这个概念听起来很陌生,但是不要担心!99.9%的情况下,你不需要禁用这个功能,它可以让你的应用以零成本提高性能。
结构共享仅适用于json兼容的值,其他类型都将被视为已更改。例如,如果您看到由于响应大而导致的性能问题,您可以使用
config.structuralSharing
配置禁用此功能。如果您正在处理查询响应中的非json值,并且仍然希望检测数据是否已更改,则可以配置config.structuralSharing
为自定义函数,根据新旧返回值计算,并且根据需要保留引用。
Caching Examples
这个示例包含以下内容:
- 有缓存和无缓存的查询实例
- 后台重新获取
- 不活跃的查询
- 垃圾回收
假设使用默认配置:gcTime为5分钟,staleTime为0
1. useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
挂载一个新实例
- 由于没有使用请求使用['todos']键进行查询,因此该查询将显示硬加载状态,并发出请求以获取数据。
- 当网络请求完成后,返回的数据将被缓存在['todos']键下。
- hooks将在配置的过期时间(默认为0或立即)之后将数据标记为过期。
2. useQuery({queryKey: ['todos'], queryFn: fetchTodos})
挂载第二个实例
- 由于缓存中已经有第一次查询的['todos']键的数据,因此该数据将立即从缓存中返回。
- 新实例将调用查询函数触发新的网络请求,
请注意,无论两个fetchTodos
查询函数是否相同,两个查询的状态都会被更新(包括isFetching
、isPending
和其他值),因为它们具有相同的queryKey,即['todos']。 - 当请求成功完成时,['todos']键下的缓存数据将使用新数据更新,并且两个实例都将使用新数据更新。
3. useQuery({queryKey: ['todos'], queryFn: fetchTodos})
查询的两个实例都被卸载并且不再使用
由于这个查询没有更多的active实例,所以使用gcTime
设置一个垃圾收集超时来删除和垃圾回收改查询(默认为5分钟)。
4. 在缓存超时之前,挂载另一个useQuery实例({queryKey: ['todos'], queryFn: fetchTodos}
)
当fetchTodos
函数在后台运行时,查询立即返回可用的缓存数据。当请求成功完成时,它将用新数据填充缓存。
5. 卸载useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
的最后一个实例
6. 5分钟内没有新的useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
实例产生
['todos']键下的缓存数据将被删除并收集垃圾。