You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:43:24