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

React递归侧边栏组件状态变更后未重新渲染问题求助

问题解决:递归嵌套导航点击切换子列表后不重新渲染

你的问题核心是状态更新时没有创建新数组,React依赖状态的引用变化触发重渲染,而你在toggleVisibility里直接修改了原数组(splice、push都是原地修改操作),导致React认为状态未改变,因此点击后组件不更新。父组件折叠/展开时触发自身重渲染,连带子组件重新渲染,此时状态是正确的,所以子列表能正常显示。

修复步骤:

  • 状态更新必须返回新数组:不要直接修改prev状态数组,而是通过创建新数组来更新状态;
  • 避免依赖DOM获取数据:直接传递object.name替代e.target.innerHTML,避免DOM结构变化导致的错误。

修改后的完整代码:

import React, { useState } from "react";
import styles from "./SidebarList.module.css";

function SidebarList(props) {
  const { data } = props;
  const [visible, setVisible] = useState([]);

  const toggleVisibility = (itemName) => {
    setVisible((prev) => {
      if (prev.includes(itemName)) {
        // 用filter创建新数组,移除指定元素
        return prev.filter(name => name !== itemName);
      } else {
        // 用扩展运算符创建新数组,添加元素
        return [...prev, itemName];
      }
    });
  };

  const hasChildren = (item) => {
    return Array.isArray(item.techniques) && item.techniques.length > 0;
  };

  const populateList = (data) => {
    return data.map((object) => {
      return (
        // 给Fragment加key,修复列表元素无key的警告
        <React.Fragment key={object.name}>
          <li
            onClick={() => toggleVisibility(object.name)}
          >
            {object.name}
          </li>

          {visible.includes(object.name) && hasChildren(object) ? (
            <ul id={object.name}>
              {populateList(object.techniques)}
            </ul>
          ) : null}
        </React.Fragment>
      );
    });
  };

  return <ul>{populateList(data)}</ul>;
}

export default SidebarList;

关键修改说明:

  1. 状态更新逻辑:
    • 移除元素时使用filter返回新数组,替代splice原地修改;
    • 添加元素时使用[...prev, itemName]创建新数组,替代push原地修改。
  2. 点击事件优化:
    • 直接在onClick中传递object.name,不再依赖e.target.innerHTML,更可靠且避免DOM相关问题;
  3. Fragment优化:
    • 给外层Fragment添加key,修复React列表元素无key的警告。

内容的提问来源于stack exchange,提问作者rs.wright

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:40:25