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

Next.js过多重渲染错误求助:动态菜单实现遇阻

解决Next.js动态菜单生成的无限重渲染问题

问题背景

需要基于固定JSON数据生成「主菜单包含子菜单」的动态菜单结构,无法修改JSON文件,开发时遇到Too many re-renders. React limits the number of renders to prevent an infinite loop错误。

错误原因

  1. 组件顶层直接执行状态更新:在组件函数顶层遍历数据并调用setMenu、setSubMenu,每次状态更新会触发组件重新渲染,重新渲染后又会重复执行状态更新操作,形成无限循环。
  2. 错误的组件类型声明:将使用useState、useEffect的Client Component标记为async,但这类组件不能是异步函数。
  3. 数据获取错误:接口返回的JSON中menus是根对象下的数组,原代码直接将整个返回对象赋值给状态,导致后续遍历逻辑出错。
  4. 冗余状态变量:用subMenu状态临时存储子菜单,多次调用setSubMenu会额外触发渲染,且子菜单可直接通过计算得到,无需单独维护状态。

修复后的代码

import { useEffect, useState } from "react";

export default function MenuCreator() {
    const [menu, setMenu] = useState([]);
    const [menuData, setMenuData] = useState([]);

    useEffect(() => {
        fetch("http://localhost:8000/menus")
            .then((res) => {
                if (!res.ok) throw Error("请求菜单数据失败");
                return res.json();
            })
            .then((data) => {
                // 从返回的JSON中提取menus数组
                setMenuData(data.menus);
            })
            .catch(err => console.error(err));
    }, []);

    // 当原始菜单数据更新时,生成带层级的菜单结构
    useEffect(() => {
        if (menuData.length === 0) return;

        // 筛选所有主菜单(main_menu为null的项)
        const mainMenus = menuData.filter(item => item.main_menu === null);
        
        // 为主菜单匹配对应的子菜单
        const structuredMenu = mainMenus.map(main => ({
            ...main,
            subMenus: menuData.filter(sub => sub.main_menu === main.id)
        }));

        setMenu(structuredMenu);
    }, [menuData]);

    return { menu };
}

关键修复说明

  • 数据处理逻辑移入useEffect:依赖menuData状态,确保仅在原始菜单数据加载完成后执行一次结构转换,避免重复触发状态更新。
  • 移除异步组件声明:Client Component不能是async函数,改为普通函数。
  • 修正数据提取逻辑:正确从返回的JSON对象中取出menus数组。
  • 简化状态管理:不再使用临时subMenu状态,直接通过数组方法计算主菜单对应的子菜单,一次性更新menu状态,减少不必要的渲染触发。

内容的提问来源于stack exchange,提问作者Samet ÖZTÜRK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:15:35