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

React应用开关侧边栏导致程序崩溃问题排查求解

React 仪表盘侧边栏切换时应用崩溃问题修复

问题现象

  • 基于React.js开发仪表盘应用时,子组件新增useState钩子逻辑后,父组件每次执行打开/关闭侧边栏操作,应用直接崩溃
  • 报错信息截图:
    React报错截图

问题代码

父组件代码

import { Button } from "primereact/button";
import axios from "axios";
import { useContext, useState } from "react";
import { UserContext } from "../contexts/UserContext";
import { useNavigate } from "react-router-dom";
import { Sidebar } from "primereact/sidebar";
import { Divider } from "primereact/divider";
import { Avatar } from "primereact/avatar";
import { Menu } from "primereact/menu";
import "primeicons/primeicons.css";
import "../styling/page-home.css";
import Settings from "../components/dashboard/Settings";
import Stats from "../components/dashboard/Stats";

export default function PageHome() {


  const context = useContext(UserContext);

  const navigate = useNavigate();

  const dummyUser = {
    username: "Jane Doe",
    email: "example@company.com",
    image: "./media/avatar-picture.jpeg",
  };

  const [content, setContent] = useState(Settings);

  let menuItems = [
    { label: "Dashboard", icon: "pi pi-fw pi-th-large" },
    { label: "Planning", icon: "pi pi-fw pi-calendar" },
    { label: "Offertes", icon: "pi pi-fw pi-file" },
    { label: "Facturen", icon: "pi pi-fw pi-euro" },
    { label: "Webshop", icon: "pi pi-fw pi-shopping-bag" },
    { label: "Statistieken", icon: "pi pi-fw pi-chart-bar", command:() => {setContent(Stats)} },
  ];

  let settings = [{ label: "Settings", icon: "pi pi-fw pi-cog", command:() => {setContent(Settings)}  }];

  const logout = () => {
    axios.post(process.env.REACT_APP_API + "/auth/logout").then((res) => {
      if (res.data.msg === "ok") {
        context.logout();
        navigate("/login");
      }
    });
  };

  const [visible, setVisible] = useState(true);

  return (
    <>
      <div className="page-home">
        <Button icon="pi pi-arrow-right" onClick={(e) => setVisible(true)} />

        <Sidebar
          showCloseIcon={false}
          className="p-0 p-sidebar-sm border-none shadow-8 z-0"
          visible={visible}
          modal={false}
          onHide={() => setVisible(false)}
        >
          <div className="sidebar-container flex flex-column justify-content-between h-full">
            <div className="sidebar-container-top">
              <div
                id="logo-box"
                className="flex flex-row align-items-center gap-3 pl-2"
              >
                <Avatar image="./media/mbt-logo.jpeg" size="medium" />
                <h3 className="opacity-50">THAN GIFTS</h3>
              </div>
              <Divider className="opacity-30"/>
              {/*User card */}
              <div className="flex flex-row align-items-center gap-3 py-5 px-2">
                <Avatar
                  className="p-0"
                  image={dummyUser.image}
                  size="large"
                  shape="circle"
                />
                <div id="avatar-info">
                  <div className="font-bold" id="avatar-info-username">
                    {dummyUser.username}
                  </div>
                  <div className="text-sm opacity-40" id="avatar-info-email">
                    {dummyUser.email}
                  </div>
                </div>
              </div>
              <Menu className="border-none" model={menuItems} />
              <Divider className="opacity-30"/>
              <Menu className="border-none" model={settings} />
            </div>
            <Button
              className="p-button-secondary p-button-text"
              onClick={() => {
                setVisible(false);
              }}
            >
              {" "}
              <i className="pi pi-fw pi-window-minimize pr-4" />
              Toggle sidebar
            </Button>
          </div>
        </Sidebar>

        <div
          id="main-container"
          className="flex flex-row justify-content-center align-items-center z-1"
          legend={context.user_name}
          style={{ marginLeft: visible ? "20rem" : "0rem" }}
        >
          {content}
        </div>
      </div>
    </>
  );
}

子组件代码

import React from "react";
import { Card } from "primereact/card";
import { Password } from "primereact/password";
import { useState } from "react";
import { Fieldset } from "primereact/fieldset";
import { InputText } from "primereact/inputtext";

export default function Settings() {
  const [password, setPassword] = useState("");
  return (
    <Card title="Settings" className="w-full m-5">
      <Fieldset legend="Wachtwoord wijzigen">
        <div className="p-4">
          <h5>Huidig wachtwoord</h5>
          <Password value={password} onChange={(e)=>{setPassword(e.target.value)}} toggleMask feedback={false}/>

          <h5>nieuw wachtwoord</h5>
          <Password toggleMask />

          <h5>herhaal wachtwoord</h5>
          <Password toggleMask feedback={false}/>
        </div>
      </Fieldset>
    </Card>
  );
}

错误原因

  • 核心问题是错误地将组件函数本身存入useState,渲染时直接输出组件函数引用而非JSX元素。
  • 这种写法违反React Hooks的调用规则:侧边栏切换时父组件触发重渲染,React无法正确追踪子组件内部useState的调用链路,直接触发渲染崩溃。

修复方案

  • 移除state中存储的组件函数引用,改为存储页面标识字符串,通过标识判断渲染对应组件
  • 核心修改代码如下:
// 原错误写法:const [content, setContent] = useState(Settings);
// 修改为存储激活页面标识
const [activePage, setActivePage] = useState('settings');

// 菜单点击事件改为修改页面标识
let menuItems = [
  { label: "Dashboard", icon: "pi pi-fw pi-th-large" },
  { label: "Planning", icon: "pi pi-fw pi-calendar" },
  { label: "Offertes", icon: "pi pi-fw pi-file" },
  { label: "Facturen", icon: "pi pi-fw pi-euro" },
  { label: "Webshop", icon: "pi pi-fw pi-shopping-bag" },
  { label: "Statistieken", icon: "pi pi-fw pi-chart-bar", command:() => {setActivePage('stats')} },
];

let settings = [{ label: "Settings", icon: "pi pi-fw pi-cog", command:() => {setActivePage('settings')}  }];
  • 渲染区域改为标准JSX组件调用写法:
<div
  id="main-container"
  className="flex flex-row justify-content-center align-items-center z-1"
  legend={context.user_name}
  style={{ marginLeft: visible ? "20rem" : "0rem" }}
>
  {activePage === 'settings' && <Settings />}
  {activePage === 'stats' && <Stats />}
</div>

修改后React可以正确识别组件、追踪Hooks调用链路,侧边栏切换触发重渲染时不会再出现崩溃问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:24:27