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

点击导航栏菜单图标触发状态更新时页面冻结崩溃求助

问题:点击导航栏菜单图标导致页面冻结崩溃

点击导航栏中切换菜单状态的图标时,页面会完全冻结并崩溃。但直接将useState初始值设为true或false时,菜单能正常显示。尝试过以下方案但均未解决:

  • 使用useEffect:页面刷新后菜单自动打开,但无法通过按钮控制状态
  • 使用useCallback:出现和直接使用useState相同的页面崩溃问题

原代码

import React, {useState} from 'react';
import {Menu} from '@mui/icons-material';

function Navbar() {
  const [menuClicked, setMenuClicked] = useState(false);

  const updateMenu = () => {
    setMenuClicked(!menuClicked)
  }

  return(
    <div className='h-16 z-20 relative'>
          <div className='fixed top-0 text-left text-6xl font-bold items-center bg-white/40  h-20 w-full flex dark:text-white dark:bg-neutral-900/40'>
              <div className='flex flex-1 items-center pb-5'>
                  <span className='pl-4'>psue</span>
              </div>

              <div className='flex justify-end w-7/12 scale-0 md:scale-100 items-center'>
                  <ul className='flex text-xl gap-12 pb-0'>
                      <li className=''>
                          <a href='/'>Home</a>
                      </li>
                      <li>
                          <a href='/livechat'>Live Chat</a>
                      </li>
                      <li>
                          {checkLogin ? (<a href='/profile'>{auth.currentUser.email.substring(0, auth.currentUser.email.indexOf('@'))}</a>) : (<a onClick={signOutFunction} href='/login'>Login</a>)}
                      </li>
                  </ul>
              </div>

              <div className='z-20 pr-5 pb-5 scale-150 overflow-x-hidden md:scale-0'>
                  <Menu onClick={() => updateMenu()} className='cursor-pointer'/>
              </div>
          </div>

          <div className={menuClicked ? 'translate-x-0 transition fixed bottom-0 top-0 right-0 h-screen w-64 z-10' : 'transition translate-x-72 fixed top-0 right-0 h-screen w-0'}>
            <div className='bg-white/30 dark:bg-neutral-900/30 dark:text-white fixed right-0 top-0 w-full h-full'>
                <ul className='flex flex-col text-xl gap-16 h-full w-full justify-center items-center backdrop-blur-lg font-bold'>
                    <li>
                      <CloseIcon onClick={() => updateMenu()} className='cursor-pointer scale-150 fixed top-24'/>
                    </li>
                    <li className=''>
                          <a href='/'>Home</a>
                      </li>
                      <li>
                          <a href='/livechat'>Live Chat</a>
                      </li>
                      <li>
                          {checkLogin ? (<a href='/profile'>{auth.currentUser.email.substring(0, auth.currentUser.email.indexOf('@'))}</a>) : (<a onClick={signOutFunction} href='/login'>Login</a>)}
                      </li>
                </ul>
            </div>
          </div>
      </div>
  )
}

export default Navbar;

问题原因分析

  1. 闭包导致状态更新异常:updateMenu里用!menuClicked切换状态时,依赖的是函数创建时捕获的旧状态值。如果组件因其他原因重渲染,这个值可能不是最新的,反复触发错误的状态更新,导致页面冻结。
  2. auth.currentUser空值未处理:当checkLogin为true,但auth.currentUser还未初始化完成时,直接访问auth.currentUser.email会抛出错误,直接导致组件崩溃。
  3. 缺失CloseIcon导入:代码里使用了CloseIcon但未从MUI图标库导入,属于运行时错误,会直接引发页面崩溃。

修复方案

1. 用函数式更新解决闭包问题

状态更新时不依赖闭包里的旧值,改用函数式更新确保拿到最新状态:

const updateMenu = () => {
  setMenuClicked(prev => !prev);
}

2. 处理auth.currentUser空值情况

在访问邮箱前先判断auth.currentUser是否存在,避免抛出错误:

{checkLogin ? (
  auth.currentUser ? (
    <a href='/profile'>{auth.currentUser.email.substring(0, auth.currentUser.email.indexOf('@'))}</a>
  ) : (
    <span>加载中...</span>
  )
) : (
  <a onClick={signOutFunction} href='/login'>Login</a>
)}

3. 导入缺失的CloseIcon

从MUI图标库补全导入:

import {Menu, CloseIcon} from '@mui/icons-material';

4. 优化菜单容器样式(可选)

原菜单容器的w-0可能导致布局异常,调整样式让过渡更稳定:

<div className={menuClicked ? 'translate-x-0 transition-all duration-300 fixed bottom-0 top-0 right-0 h-screen w-64 z-10' : 'translate-x-full transition-all duration-300 fixed top-0 right-0 h-screen w-64 z-10 invisible'}>

修复后完整代码

import React, {useState} from 'react';
import {Menu, CloseIcon} from '@mui/icons-material';

function Navbar() {
  const [menuClicked, setMenuClicked] = useState(false);

  const updateMenu = () => {
    setMenuClicked(prev => !prev);
  }

  return (
    <div className='h-16 z-20 relative'>
      <div className='fixed top-0 text-left text-6xl font-bold items-center bg-white/40  h-20 w-full flex dark:text-white dark:bg-neutral-900/40'>
        <div className='flex flex-1 items-center pb-5'>
          <span className='pl-4'>psue</span>
        </div>

        <div className='flex justify-end w-7/12 scale-0 md:scale-100 items-center'>
          <ul className='flex text-xl gap-12 pb-0'>
            <li className=''>
              <a href='/'>Home</a>
            </li>
            <li>
              <a href='/livechat'>Live Chat</a>
            </li>
            <li>
              {checkLogin ? (
                auth.currentUser ? (
                  <a href='/profile'>{auth.currentUser.email.substring(0, auth.currentUser.email.indexOf('@'))}</a>
                ) : (
                  <span>加载中...</span>
                )
              ) : (
                <a onClick={signOutFunction} href='/login'>Login</a>
              )}
            </li>
          </ul>
        </div>

        <div className='z-20 pr-5 pb-5 scale-150 overflow-x-hidden md:scale-0'>
          <Menu onClick={updateMenu} className='cursor-pointer'/>
        </div>
      </div>

      <div className={menuClicked ? 'translate-x-0 transition-all duration-300 fixed bottom-0 top-0 right-0 h-screen w-64 z-10' : 'translate-x-full transition-all duration-300 fixed top-0 right-0 h-screen w-64 z-10 invisible'}>
        <div className='bg-white/30 dark:bg-neutral-900/30 dark:text-white fixed right-0 top-0 w-full h-full'>
          <ul className='flex flex-col text-xl gap-16 h-full w-full justify-center items-center backdrop-blur-lg font-bold'>
            <li>
              <CloseIcon onClick={updateMenu} className='cursor-pointer scale-150 fixed top-24'/>
            </li>
            <li className=''>
              <a href='/'>Home</a>
            </li>
            <li>
              <a href='/livechat'>Live Chat</a>
            </li>
            <li>
              {checkLogin ? (
                auth.currentUser ? (
                  <a href='/profile'>{auth.currentUser.email.substring(0, auth.currentUser.email.indexOf('@'))}</a>
                ) : (
                  <span>加载中...</span>
                )
              ) : (
                <a onClick={signOutFunction} href='/login'>Login</a>
              )}
            </li>
          </ul>
        </div>
      </div>
    </div>
  )
}

export default Navbar;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:06:29