React Query 的请求怎么避免重复触发?

Air-丹丹 阅读 55

我在用 React Query 做一个用户列表页,每次组件挂载都会自动发请求,但切换 tab 再回来又会重新请求一次,明明数据没变啊。

我试过把 enabled 设成 false 手动控制,但这样 initialData 就不生效了,而且逻辑变得很绕。有没有办法让 query 在已有缓存的情况下别重复发请求?

我的代码大概是这样的:

const { data } = useQuery({
  queryKey: ['users'],
  queryFn: fetchUsers,
  staleTime: 5 * 60 * 1000, // 5分钟
  cacheTime: 10 * 60 * 1000
})

按理说 staleTime 里应该直接用缓存才对,但它还是每次都重新请求,是我哪里理解错了?

我来解答 赞 15 收藏
二维码
手机扫码查看
2 条解答
极客艺霖
你的理解有个关键点搞错了。staleTime 的作用是"数据新鲜度",决定的是数据过期后是否自动后台刷新,但它管不了组件重新挂载这事儿。

切换 tab 时如果组件完全卸载再挂载,React Query 默认行为就是会重新请求,除非你明确告诉它不要。

几个解决方案:

方案一:禁止挂载时重新请求

const { data } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000,
refetchOnMount: false // 挂载时不重新请求
})


方案二:禁止窗口焦点重新请求

const { data } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false // 切换回来时不重新请求
})


方案三:如果用 React Query v5,用 placeholderData 保持旧数据

const { data } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000,
placeholderData: keepPreviousData // v5写法
})


React Query v4 对应的是 keepPreviousData: true

你的场景用方案一+方案二组合基本够用了。如果 tab 切换时组件其实没有卸载,只是隐藏,那问题可能出在你给每个 tab 下的 query 设的 key 不一样,或者用了什么奇怪的 key 写法导致缓存没命中。先检查一下 queryKey 在切换前后是否真的保持一致。
点赞
2026-03-13 22:37
爱学习的万华
你这个情况很常见,其实 React Query 的缓存机制比你想象的要复杂点。首先确认下你的 queryKey 是不是完全一致,包括参数顺序,React Query 会把它当作缓存的唯一标识。

关于 staleTime 的理解有点偏差,它控制的是数据过期后是否重新请求,不是是否使用缓存。要实现你想要的效果,需要结合 staleTimerefetchOnMount 这两个参数:

const { data } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000,
cacheTime: 10 * 60 * 1000,
refetchOnMount: false // 关键在这里
})


另外还有个更精细的控制方式是用 refetchOnMount 的智能模式:
refetchOnMount: 'always' | 'ifStale' | false


默认值是 'always' 所以会一直重新请求,改成 'ifStale' 就会只在数据过期时重新请求。

还有个坑要注意:如果你在开发时用了 React.StrictMode,它会故意重复挂载组件来检测问题,这时候可以把 staleTime 设大点或者关掉严格模式测试下。

我一般习惯这么配:
{
staleTime: 1000 * 60 * 5, // 5分钟
cacheTime: 1000 * 60 * 15, // 15分钟
refetchOnMount: 'ifStale',
refetchOnWindowFocus: false // 切换窗口也不重新请求
}


这样基本就能满足大多数列表页的需求了,数据不会频繁重新请求,用户体验也好。
点赞 2
2026-03-08 14:20