React Query预加载时为什么会出现重复请求?
我在用React Query做页面预加载时遇到问题,设置了staleTime和keepPreviousData,但每次刷新页面还是会触发两次请求:
我的查询配置是这样的:
useQuery(['posts'], fetchPosts, {
staleTime: 1000 * 60 * 5,
keepPreviousData: true,
refetchOnWindowFocus: false
})
控制台显示:先看到预加载时的pending请求,页面渲染完成后再来一个新的请求。用React devtools看缓存数据确实存在,但网络面板显示重复了。这是预加载的CSS样式:
.loading {
opacity: 0.5;
pointer-events: none;
transition: opacity 0.3s;
}
尝试过设置enabled: false手动控制,但和路由守卫配合时又会出现数据不同步的问题,有没有更好的解决办法?
React Query默认会在组件挂载时重新发起请求,除非明确告诉它不要这么做。你设置了
staleTime,但这个值只控制数据是否被认为是“陈旧”的,并不能完全阻止重复请求。另外,keepPreviousData的作用是保留前一个查询结果,但它也不会影响组件挂载时的重新请求行为。解决这个问题的关键是调整查询的触发逻辑。可以试试用
initialData或者更精确地控制enabled选项。不过手动控制enabled确实容易导致路由守卫中的数据不同步问题,所以这里推荐另一种方式:把预加载的数据直接写入React Query的缓存中,这样组件挂载时就不会重新发起请求了。具体做法是使用
queryClient.setQueryData来设置初始数据。代码可以这么写:这样一来,预加载的数据会直接进入缓存,组件挂载时发现缓存中有有效数据,就不会再发起重复请求了。
还有一点要注意,确保你的
fetchPosts函数是幂等的,也就是多次调用不会产生副作用。如果还是有问题,建议检查一下路由切换时的组件卸载和重新挂载逻辑,有时候问题可能出在这里。在服务端渲染时,React Query会先触发一次查询来获取数据,等页面到了客户端,它又会再触发一次查询来确保数据是最新的。虽然你设置了staleTime和keepPreviousData,但这些配置对服务端渲染的数据同步没啥帮助。
解决这个问题的关键是用
hydrate方法把服务端的数据正确传递到客户端。你可以在服务端渲染时,把查询结果序列化后注入到HTML里,比如在WordPress主题里加一段脚本:然后在客户端初始化React Query的时候,用
hydrate方法把这些数据喂给它:这样处理之后,客户端就会直接使用服务端传过来的数据,不会再发重复请求了。记得在服务端也要用相同的查询key来获取数据,这样才能保证两边的数据结构一致。
还有个小技巧,如果你用的是next.js或者类似的框架,可以直接用它们提供的数据预取功能,效果会更好。不过在WordPress环境下,上面这个方法就够用了。调试的时候可以用React Devtools检查下hydration后的状态是不是正确的,省得踩坑。