React Query useInfiniteQuery取消点赞后组件重取数据原因排查
以下是几个常见的原因和排查方向:
1. 误触了invalidateQueries导致缓存失效
你写的useUnlikePost大概率是基于useMutation实现的,如果在mutation的onSuccess、onError或者乐观更新的回调里调用了queryClient.invalidateQueries(),哪怕已经做了乐观更新,React Query还是会触发全量数据重新获取,直接导致组件重新加载。
排查方法:检查useMutation的配置,移除不必要的invalidateQueries调用。乐观更新已经手动修改了缓存,成功后不需要再触发重新拉取;失败时只需要回滚缓存即可。
示例正确写法:
const useUnlikePost = () => { const queryClient = useQueryClient(); return useMutation( (postId) => api.unlikePost(postId), // 你的取消点赞API { // 乐观更新缓存 onMutate: async (postId) => { // 先暂停可能的重新获取 await queryClient.cancelQueries(['posts']); // 保存当前缓存用于回滚 const previousPosts = queryClient.getQueryData(['posts']); // 更新无限查询的缓存结构 queryClient.setQueryData(['posts'], (data) => { if (!data) return data; return { ...data, pages: data.pages.map(page => ({ ...page, posts: page.posts.map(post => post.id === postId ? { ...post, liked: false, likeCount: post.likeCount - 1 } : post ) })) }; }); // 返回上下文用于回滚 return { previousPosts }; }, onError: (err, postId, context) => { // 错误时回滚缓存 queryClient.setQueryData(['posts'], context.previousPosts); }, // 不要在这里调用invalidateQueries! onSuccess: () => { // 无需额外操作,缓存已经是最新的 } } ); };
2. 乐观更新时没有正确处理useInfiniteQuery的缓存结构
useInfiniteQuery的缓存是一个包含pages数组和pageParams数组的对象,每个page里才是你实际的帖子列表。如果乐观更新时没有遍历pages修改对应帖子,而是直接修改了顶层数据,会导致缓存结构损坏,React Query识别到缓存异常后会触发重新获取。
排查方法:检查setQueryData的逻辑,确保遍历data.pages,逐个修改每个页面里的目标帖子,保持缓存结构和API返回的一致。
3. queryKey意外变化触发重新查询
如果useInfiniteQuery的queryKey包含了某些可变状态(比如用户ID、筛选条件),而取消点赞操作不小心修改了这些状态值,会导致queryKey变化,React Query会认为是新的查询,重新发起请求并重新渲染组件。
排查方法:检查useInfiniteQuery的queryKey定义,确保取消点赞操作不会修改queryKey中的任何依赖项。比如:
// 正确:queryKey里的参数不会被取消点赞操作修改 useInfiniteQuery(['posts', currentUserId], fetchPosts, { ... }); // 错误:如果cancelLike操作修改了某个筛选参数,会导致queryKey变化 useInfiniteQuery(['posts', currentUserId, filterParams], fetchPosts, { ... });
4. staleTime设置过短导致后台自动重新获取
React Query默认staleTime为0,意味着数据一旦被修改(包括乐观更新)就会标记为"过期",随后会自动在后台重新获取数据,这会导致组件重新加载。
排查方法:给useInfiniteQuery设置合适的staleTime,比如设置为5分钟或者更长,避免数据频繁过期:
useInfiniteQuery(['posts'], fetchPosts, { staleTime: 5 * 60 * 1000, // 5分钟 // 其他配置... });
5. 误开启了自动重新获取的配置
检查useInfiniteQuery的refetchOnMount、refetchOnAppFocus(React Native专属配置)等参数,这些默认是true,如果在取消点赞时恰好触发了这些事件(比如操作时APP切到后台又回来),也会导致重新加载。可以根据需求关闭这些配置:
useInfiniteQuery(['posts'], fetchPosts, { refetchOnMount: false, refetchOnAppFocus: false, // 其他配置... });
内容的提问来源于stack exchange,提问作者Muteshi

