React - 警告:无法在呈现不同组件(`Modules`)时更新组件(`PrivateRoute`)

React - Warning: Cannot update a component (`PrivateRoute`) while rendering a different component (`Modules`)

在所有子组件上出现以下错误。

react-dom.development.js:86 Warning: Cannot update a component (PrivateRoute) while rendering a different component (Example). To locate the bad setState() call inside Examples,

我发现了很多相同错误的例子,但到目前为止还没有解决方案 React Route Warning: Cannot update a component (`App`) while rendering a different component (`Context.Consumer`) Can Redux cause the React warning "Cannot update a component while rendering a different component"

如果未登录,PrivateRoute 将组件包装为重定向。

export default function PrivateRoute() {
  const session: ISessionReducer = useSelector((state: RootState) => state.core.session);

  useEffect(() => {
    if (!session.jwt) <Navigate to="/login" />;
  }, [session]);

  return <Outlet />;
};

这是因为 useEffect 在组件渲染后运行。所以在这种情况下发生的事情是 Outlet 组件在 useEffect 中的代码运行之前首先呈现。因此,如果 jwt token 不存在,那么它会尝试重定向,但无法重定向,因为到那时您的 Outlet 已经呈现。

所以我可以给你我用来检查 jwt token 是否存在的解决方案。

1.) 我创建了一个自定义挂钩来检查 token 是否存在。
2.) 然后我在 privateRoute 组件中使用自定义挂钩来检查用户是否已登录。

useAuthStatus.js

import { useState, useEffect } from 'react'
import { useSelector } from 'react-redux'

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

  const { user } = useSelector((state) => state.auth)

  useEffect(() => {
    if (user?.token) {
      setLoggedIn(true)
    } else {
      setLoggedIn(false)
    }

    setCheckingStatus(false)
  }, [user?.token])

  return { loggedIn, checkingStatus }
}

PrivateRoute component

import { Navigate, Outlet } from 'react-router-dom'
import { useAuthStatus } from '../../hooks/useAuthStatus'
import CircularProgress from '@mui/material/CircularProgress'

const PrivateRoute = () => {
  const { loggedIn, checkingStatus } = useAuthStatus()

  if (checkingStatus) {
    return <CircularProgress className='app__modal-loader' />
  }

  return loggedIn ? <Outlet /> : <Navigate to='/login' />
}

export default PrivateRoute