React应用开关侧边栏导致程序崩溃问题排查求解
React 仪表盘侧边栏切换时应用崩溃问题修复
问题现象
- 基于React.js开发仪表盘应用时,子组件新增
useState钩子逻辑后,父组件每次执行打开/关闭侧边栏操作,应用直接崩溃 - 报错信息截图:

问题代码
父组件代码
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
相关产品推荐
相关产品推荐

