React-Query条件启用查询:避免重复执行筛选器校验函数
解决React Query中筛选器合法性判断重复执行的问题
直接在useQuery的enabled属性中调用isFiltersValid(filters),会导致该函数在组件每次重渲染时都执行——哪怕筛选器本身没有变化,这对重计算逻辑来说会造成不必要的性能损耗。如果不想用useMemo缓存结果或用状态存储合法性状态,你可以手动通过useRef来缓存筛选器和对应的合法性结果,仅在筛选器实际变更时重新计算。
方案实现
1. 实现浅比较函数(针对复杂对象类型的筛选器)
如果你的筛选器是对象/数组这类引用类型,需要用浅比较来判断是否真的变更:
function shallowEqual(objA, objB) { if (objA === objB) return true; if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } const keysA = Object.keys(objA); if (keysA.length !== Object.keys(objB).length) return false; for (const key of keysA) { if (!Object.prototype.hasOwnProperty.call(objB, key) || objA[key] !== objB[key]) { return false; } } return true; }
2. 在组件中用useRef缓存结果
import { useQuery, useRef } from '@tanstack/react-query'; // 假设你的筛选器和合法性判断函数 const filters = { /* 筛选条件 */ }; function isFiltersValid(filters) { // 重计算逻辑 } function YourComponent() { const filtersRef = useRef(filters); const isValidRef = useRef(isFiltersValid(filters)); // 仅当筛选器实际变更时,重新计算合法性 if (!shallowEqual(filters, filtersRef.current)) { filtersRef.current = { ...filters }; // 浅拷贝避免引用混淆 isValidRef.current = isFiltersValid(filtersRef.current); } const { data } = useQuery({ queryKey: ['data', filters], queryFn: () => fetch('/api/data', { method: 'POST', body: JSON.stringify(filters) }), enabled: isValidRef.current, }); // 组件渲染逻辑 return <div>{/* ... */}</div>; }
如果你的筛选器是字符串、数字这类原始类型,可以简化对比逻辑,直接用===判断:
const filtersRef = useRef(filters); const isValidRef = useRef(isFiltersValid(filters)); if (filters !== filtersRef.current) { filtersRef.current = filters; isValidRef.current = isFiltersValid(filters); }
方案说明
这个方法的本质是手动实现了类似useMemo的缓存逻辑:通过useRef保存上一次的筛选器和合法性结果,每次渲染时先对比当前筛选器与缓存的筛选器,只有当两者确实不同时,才重新执行isFiltersValid并更新缓存。这样就能避免无关重渲染时的重复计算。
内容的提问来源于stack exchange,提问作者Gnanavel
相关产品推荐
相关产品推荐

