useEffect与useSelector引发无限循环的异常问题排查
问题原因与解决办法
核心原因
每次组件渲染时,useSelector里的filter方法都会返回一个新的数组引用——哪怕数组内容完全没变。React的依赖对比是基于引用的,所以data会被判定为每次都“变了”,导致监听data的useEffect反复执行。而useEffect里调用setList会触发组件重新渲染,重新渲染又会让useSelector生成新数组,形成无限循环。
解决办法
1. 给useSelector加缓存(推荐)
使用createSelector(来自@reduxjs/toolkit)创建记忆化的选择器,只有当state.basicSetting或者过滤条件变化时,才会重新计算返回值,避免每次渲染都生成新数组:
import { createSelector } from '@reduxjs/toolkit'; const selectBasicSetting = (state: DeviceList) => state.basicSetting; const filteredDataSelector = createSelector( [selectBasicSetting], (basicSetting) => { if (basicSetting !== null) { return basicSetting.filter( item => item.deviceName.includes('ac') && !item.deviceName.includes('bz') ); } return null; } ); // 组件内使用 const data = useSelector(filteredDataSelector);
2. 用useMemo替代useEffect维护衍生状态
list本质是data的衍生状态,不需要单独存在useState里,直接用useMemo缓存计算结果即可:
const data = useSelector((state: DeviceList) => { if (state.basicSetting !== null) { return state.basicSetting.filter( item => item.deviceName.includes('ac') && !item.deviceName.includes('bz'), ); } else { return null; } }); const list = useMemo(() => { if (data === null) return []; const arr = []; for (let i = 0; i < data.length; i += 4) { arr.push(data.slice(i, i + 4)); } return arr; }, [data]);
这样list只会在data内容真正变化时重新计算,不会触发多余渲染。
另外你代码里的JSON.parse(JSON.stringify(arr))完全没必要——slice已经返回新数组,深拷贝反而会生成新引用,加重不必要的渲染。
内容的提问来源于stack exchange,提问作者user19539777
相关产品推荐
相关产品推荐

