React Query 性能优化的常见瓶颈和解决方案有哪些?
React Query 最大性能陷阱是组件过度渲染:query 数据变化时所有订阅组件都重渲染。解法是用 select 提取组件关心的子字段,select 返回值用浅比较去重,相等则跳过渲染。第二陷阱是缓存策略不当:staleTime 控制数据何时标记为过期触发重新请求(默认0即立即过期),gcTime(v5 前叫 cacheTime)控制未使用的缓存何时被垃圾回收(默认5分钟)。不常变的数据应设较长 staleTime 避免无谓请求。第三是 queryKey 设计:key 变化就触发新请求,key 中包含频繁变化的值(如时间戳)会导致缓存失效。queryKey 应稳定且分层:['users', 'list', { status: 'active' }]。
追问
staleTime 和 gcTime 有什么区别? staleTime 决定数据是否需要重新获取(过期前用缓存,过期后下次挂载或窗口聚焦时 refetch);gcTime 决定缓存数据在内存中保留多久,观察者归零后开始倒计时,到期彻底删除。一个管新鲜度,一个管生命周期。
select 怎么避免不必要的渲染? select 每次查询都会执行,但只有返回值与上次浅比较不同时才触发渲染。返回新对象/数组每次都是新引用会失效,需确保返回原始值或用结构化分享的子集。
useInfiniteQuery 如何优化? 每页数据独立缓存,默认所有页面变化都触发渲染。可用 select 只取当前视口需要的数据;配合虚拟滚动(如 react-virtual)避免渲染长列表;getNextPageParam 返回 undefined 自动停止加载。
如何实现乐观更新? 用 useMutation 的 onMutate 在请求发出前乐观修改缓存(queryClient.setQueryData),onError 时用 onMutate 保存的快照回滚,onSettled 时 invalidate 相关 query 保证最终一致。
写段代码
javascript// select + staleTime 减少渲染和请求 const { data: name } = useQuery({ queryKey: ['user', id], queryFn: () => fetchUser(id), staleTime: 5 * 60 * 1000, select: (data) => data.name, });