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

Next.js 13新手求助:列表过滤时陷入无限循环

Next.js 13 Context过滤列表无限循环问题解决

核心问题根源

无限循环本质是「组件重渲染→状态更新→再重渲染」的死循环,结合你的场景,大概率是这几个原因:

  • Context Provider里每次渲染都生成新的状态值(比如直接在组件内定义数组/对象,没通过useState初始化)
  • 过滤逻辑每次渲染都产出新数组,触发Context状态频繁更新
  • useEffect依赖项设置错误,或者依赖了每次渲染都会变的值
  • 组件顶层直接调用状态更新函数(比如过滤后直接setList,没加条件判断)

具体修复方案

1. 规范Context的状态管理

别在Provider组件顶层直接调用API或创建新数组,必须用useState+useEffect初始化数据,只在挂载时获取一次:

// 正确的Context Provider写法
export function ListProvider({ children }) {
  const [rawList, setRawList] = useState([]);
  const [filteredList, setFilteredList] = useState([]);

  // 仅组件挂载时拉取原始列表
  useEffect(() => {
    async function getList() {
      const res = await fetch('/api/your-list');
      const data = await res.json();
      setRawList(data);
      setFilteredList(data);
    }
    getList();
  }, []);

  // 用useCallback包裹过滤函数,保证引用稳定
  const handleFilter = useCallback((condition) => {
    const result = rawList.filter(item => item.status === condition);
    setFilteredList(result);
  }, [rawList]);

  return (
    <ListContext.Provider value={{ rawList, filteredList, handleFilter }}>
      {children}
    </ListContext.Provider>
  );
}

2. 避免在组件顶层执行过滤+更新

如果你的Main组件直接在顶层写过滤并调用状态更新,必然触发循环,要把过滤逻辑放到useEffect或用useMemo计算:

// Main组件正确写法
const { rawList, filteredList, handleFilter } = useContext(ListContext);
const [filterKey, setFilterKey] = useState('');

// 仅当过滤条件或原始列表变化时执行过滤
useEffect(() => {
  handleFilter(filterKey);
}, [filterKey, rawList, handleFilter]);

// 如果过滤结果不需要全局共享,直接用useMemo本地计算更高效
const localFiltered = useMemo(() => {
  return rawList.filter(item => item.name.includes(filterKey));
}, [rawList, filterKey]);

3. 修正useEffect依赖项

如果过滤函数是在Context里定义的,一定要用useCallback包裹,否则每次渲染都会生成新函数,导致useEffect频繁触发。

4. localStorage的正确用法

用localStorage存列表时,只在初始化时读取,不要每次渲染都写入:

// Context初始化时从localStorage取数据
const [rawList, setRawList] = useState(() => {
  const saved = localStorage.getItem('list-data');
  return saved ? JSON.parse(saved) : [];
});

// 拉取API数据后再写入localStorage
useEffect(() => {
  async function getList() {
    const res = await fetch('/api/your-list');
    const data = await res.json();
    setRawList(data);
    localStorage.setItem('list-data', JSON.stringify(data));
  }
  // 只有本地没数据时才调用API
  if (rawList.length === 0) getList();
}, [rawList.length]);

快速排查步骤

  1. 检查Context Provider里有没有每次渲染都会执行的API调用或状态初始化
  2. 看Main组件是不是在顶层直接调用set开头的状态更新函数
  3. 用React DevTools的Profiler工具,看哪些组件频繁重渲染,定位触发源
  4. 确保传给Context的函数、对象都是稳定的(用useCallback、useMemo包裹)

内容的提问来源于stack exchange,提问作者NoName

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 15:40:20