React自定义Hook useListFunctions路由切换后缓存旧数据导致过滤器失效问题排查求助
React自定义Hook useListFunctions路由切换后缓存旧数据导致过滤器失效问题排查求助
Hey,我来帮你梳理下这个问题的可能原因和解决方案~
首先,从你的描述来看,核心问题是:路由切换回Customers页面后,URL依然保留着?age=greaterThan_40的查询参数,但调用extractQueryStringFilters()却返回空数组,这大概率是因为直接读取document.location没有同步到最新的路由状态,或者组件没有在路由变化时重新计算过滤器值。
问题根源分析
- 直接读取
document.location的局限性:React Router的路由切换是异步的,当组件重新渲染时,document.location可能还没更新到最新的路由状态;另外,如果组件被缓存(比如用了React.memo或类似的缓存策略),组件不会自动重新渲染,导致过滤器值停留在旧状态。 extractFilter函数的参数错误:你在extractFilter里调用extractLocalStorageFilter时传了3个参数,但这个函数只接受1个参数(property),这会导致你无法正确读取LocalStorage中的过滤器值,虽然这可能不是当前问题的直接原因,但也是需要修复的bug。
解决方案
1. 改用React Router的useLocation监听路由变化
通过React Router提供的useLocation Hook,我们可以精准获取当前路由的状态,并且当路由变化时自动触发组件重新渲染,确保过滤器值始终是最新的。
2. 修复extractFilter的参数错误
把extractLocalStorageFilter(entityType, entityType, property)改成extractLocalStorageFilter(property),保证参数传递正确。
3. 优化Hook,让过滤器计算依赖路由状态
修改后的useListFunctions Hook代码如下:
import { useLocation } from 'react-router-dom'; // 引入useLocation const useListFunctions = (entityType) => { const location = useLocation(); // 获取当前路由信息 const filterOperator = { containing: 'containing', equalTo: 'equalTo', greaterThan: 'greaterThan', greaterThanOrEqualTo: 'greaterThanOrEqualTo', in: 'in', lessThan: 'lessThan', lessThanOrEqualTo: 'lessThanOrEqualTo', notEqualTo: 'notEqualTo', notIn: 'notIn' }; const extractFilters = array => array .filter(([key, value]) => { const operator = value && value.split('_')[0]; return operator && Object.keys(filterOperator).map(i => i.toLowerCase()).includes(operator?.toLowerCase()); }) .map(([key, value]) => { return { property: key, operator: value && value.split('_')[0], value: value && value.split('_')[1] }; }); // 修改为接收search参数,而非直接读取document.location.search const extractQueryStringFilters = (search = location.search) => extractFilters(Array.from(new URLSearchParams(search))); const extractLocalStorageFilters = () => { const entries = Array.from(Object.entries(window.localStorage)) .filter(i => i[0].startsWith(entityType)) .map(i => [i[0].replace(`${entityType}_`, ''), i[1]]); // 去掉重复的replace,一次就够了 return extractFilters(entries); }; const extractQueryStringFilter = property => extractQueryStringFilters().find(i => i.property === property); const extractLocalStorageFilter = property => extractLocalStorageFilters().find(i => i.property === property); const extractFilter = property => { const queryFilter = extractQueryStringFilter(property); if (queryFilter) { return queryFilter; } // 修复参数错误 const localStorageFilter = extractLocalStorageFilter(property); if (localStorageFilter) { return localStorageFilter; } return null; }; return { extractFilter, extractFilters, extractLocalStorageFilter, extractLocalStorageFilters, extractQueryStringFilter, extractQueryStringFilters, }; }; export default useListFunctions;
4. 在组件中确保过滤器值随路由变化更新
在你的Customers.jsx中,不需要额外修改太多,因为useLocation会在路由变化时触发组件重新渲染,extractQueryStringFilters()会自动重新计算最新的过滤器值:
const { extractQueryStringFilters } = useListFunctions('Customer'); const filters = extractQueryStringFilters(); // 路由变化时会自动重新计算
额外建议
- 如果你的项目没有使用React Router,那可以考虑监听
popstate事件来捕获URL变化,然后通过useState和useEffect来更新过滤器状态。 - 可以给
extractQueryStringFilters添加缓存(比如用useMemo),避免每次渲染都重复计算,提升性能:
const extractQueryStringFilters = useMemo(() => { return extractFilters(Array.from(new URLSearchParams(location.search))); }, [location.search]); // 依赖location.search变化时重新计算
这样修改后,路由切换回Customers页面时,就能正确读取到URL中的查询参数,返回正确的过滤器数组了~
备注:内容来源于stack exchange,提问作者Json Dimas
相关产品推荐
相关产品推荐

