轮询(Polling)
refetchInterval 使查询按定时器重新拉取。将其设为以毫秒为单位的数字,查询将在至少存在一个活跃观察者时,每隔 N 毫秒执行一次:
1useQuery({2 queryKey: ['prices'],3 queryFn: fetchPrices,4 refetchInterval: 5 * 1000, // every 5 seconds5})轮询与 staleTime 相互独立。即使查询处于新鲜状态,仍会按计划轮询;有关 staleTime 如何与其他重新拉取行为交互,请参阅 重要默认值。refetchInterval 始终基于自身的计时器触发,不受新鲜度影响。
根据查询状态动态调整轮询间隔
可传入一个函数而非数字,以根据当前查询状态计算轮询间隔。该函数接收 Query 对象,应返回以毫秒为单位的数字,或返回 false 以停止轮询:
1useQuery({2 queryKey: ['job', jobId],3 queryFn: () => fetchJobStatus(jobId),4 refetchInterval: (query) => {5 // Stop polling once the job finishes6 if (query.state.data?.status === 'complete') return false7 return 2 * 10008 },9})返回 false 将清除间隔定时器。若查询结果发生变化,导致该函数再次返回正数,则轮询将自动恢复。
后台轮询
默认情况下,当浏览器标签页失去焦点时,轮询会暂停。对于仪表盘或任何需要在用户切换至其他标签页时仍保持数据实时性的界面,可禁用该行为:
1useQuery({2 queryKey: ['portfolio'],3 queryFn: fetchPortfolio,4 refetchInterval: 30 * 1000,5 refetchIntervalInBackground: true,6})暂停轮询
向 refetchInterval 传入一个函数,并在其中闭包捕获组件状态,从而控制轮询何时运行:
1useQuery({2 queryKey: ['prices', tokenAddress],3 queryFn: () => fetchPrice(tokenAddress),4 refetchInterval: () => {5 if (!tokenAddress || isPaused) return false6 return 15 * 10007 },8})支持离线场景的轮询
TanStack Query 通过监听浏览器的 online 和 offline 事件来检测网络连接状态。在这些事件无法可靠触发的环境中(例如 Electron、某些嵌入式 WebView),可设置 networkMode: 'always' 以跳过连接性检查:
1useQuery({2 queryKey: ['chainStatus'],3 queryFn: fetchChainStatus,4 refetchInterval: 10 * 1000,5 networkMode: 'always',6})有关网络模式的更多信息,请参阅 网络模式(Network Mode)。
关于去重的说明
每个 QueryObserver(即每个使用 useQuery 并配置了 refetchInterval 的组件)均运行自己的定时器。两个订阅相同查询键且均设置了 refetchInterval: 5 * 1000 的组件,各自都会每 5 秒触发一次定时器。真正被去重的是并发进行中的拉取请求:若两个定时器同时触发,则仅发出一次网络请求。定时器作用于观察者层级,而去重则发生在查询层级。
关于重新渲染的说明
当轮询响应返回的数据与之前相同时,仅读取 data 的组件不会重新渲染。结构共享保留了 data 的引用,而受追踪属性机制可防止因组件未使用的属性变更所引发的重新渲染(参见 渲染优化(Render Optimizations))。但若读取了如 isFetching 这类在每次轮询周期中都会变化的属性,则会触发重新渲染。
因此,在渲染过程中基于当前时间计算出的值,只要数据未变,就不会更新。例如,本应在 30 秒后显示的消息(如“此操作耗时超出预期”)可能永远不会出现。依赖时间的 UI 状态应使用独立的定时器来更新。
非浏览器环境
对于 React Native 等非浏览器运行时,标准的 online/offline 及焦点事件不可用。React Native 指南 介绍了如何将 focusManager 和 onlineManager 连接到原生应用状态 API。