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

React自定义Auth Hook及私有路由引发Maximum update depth exceeded错误求助

解决React中Maximum update depth exceeded错误(私有路由+Firebase Auth场景)

问题重现

自定义Auth状态Hook及私有路由代码如下:

自定义Hook useAuthStatus

import { getAuth, onAuthStateChanged } from 'firebase/auth'
import { useState, useEffect } from 'react'

export function useAuthStatus() {
    const [loggedIn, setLoggedIn] = useState(false)
    const [checkingStatus, setCheckingStatus] = useState(true)

    useEffect(()=>{
        const auth = getAuth()
        onAuthStateChanged(auth , (user)=>{
            if(user){
                setLoggedIn(true)
            }
            setCheckingStatus(false)
        })
        console.log("hello")

    }, [])
  return {loggedIn, checkingStatus}
}

私有路由组件 PrivateRoute

import {useAuthStatus} from '../hooks/useAuthStatus'
import { Outlet , Navigate} from 'react-router-dom'
    
function PrivateRoute() {
    const {loggedIn, checkingStatus} = useAuthStatus();
    if(checkingStatus){
        return <div>looding...</div>
    }
  return loggedIn ? <Outlet/> : <Navigate to="/auth/sign-in"/>
}

export default PrivateRoute

运行时触发错误:Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array


错误原因分析

  1. 无限路由跳转循环:若PrivateRoute被错误应用到了/auth/sign-in等登录页面路由上,会形成死循环:未登录时触发跳转至/sign-in,而/sign-in路由又被PrivateRoute保护,再次检查登录状态并跳转,最终触发更新深度超限。
  2. 未清理Firebase Auth订阅:onAuthStateChanged会持续监听Auth状态,若不主动取消订阅,可能导致内存泄漏,甚至在组件卸载后触发状态更新引发异常渲染。

修复方案

1. 修正路由配置,隔离私有/公开路由

确保PrivateRoute仅包裹需要登录权限的页面(如仪表盘),登录页面等公开路由直接配置,不被PrivateRoute嵌套:

import { Routes, Route } from 'react-router-dom';
import PrivateRoute from './PrivateRoute';
import Dashboard from './Dashboard';
import SignIn from './auth/SignIn';

function App() {
  return (
    <Routes>
      {/* 公开路由:无需登录即可访问 */}
      <Route path="/auth/sign-in" element={<SignIn />} />
      
      {/* 私有路由:仅登录用户可访问 */}
      <Route element={<PrivateRoute />}>
        <Route path="/dashboard" element={<Dashboard />} />
        {/* 其他需要权限的路由 */}
      </Route>
    </Routes>
  );
}

2. 清理Firebase Auth订阅

在useAuthStatus的useEffect中添加订阅清理逻辑,避免内存泄漏:

import { getAuth, onAuthStateChanged } from 'firebase/auth'
import { useState, useEffect } from 'react'

export function useAuthStatus() {
    const [loggedIn, setLoggedIn] = useState(false)
    const [checkingStatus, setCheckingStatus] = useState(true)

    useEffect(()=>{
        const auth = getAuth()
        // 保存取消订阅函数
        const unsubscribe = onAuthStateChanged(auth , (user)=>{
            setLoggedIn(!!user); // 简化状态更新逻辑,直接将user转为布尔值
            setCheckingStatus(false)
        })

        // 组件卸载时取消订阅
        return () => unsubscribe();
    }, [])

    return {loggedIn, checkingStatus}
}

3. 优化私有路由组件

修正拼写错误,并添加replace属性避免浏览器历史记录堆积:

import {useAuthStatus} from '../hooks/useAuthStatus'
import { Outlet , Navigate} from 'react-router-dom'
    
function PrivateRoute() {
    const {loggedIn, checkingStatus} = useAuthStatus();
    
    if(checkingStatus){
        return <div>Loading...</div>
    }
    
    return loggedIn ? <Outlet/> : <Navigate to="/auth/sign-in" replace />
}

export default PrivateRoute

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:35:18