React子路由无法渲染:PrivateRoutes状态更新异常求助
React 私有路由状态更新异常问题解决
我编写了PrivateRoutes.js用于校验用户认证状态,以此决定渲染Profile组件或跳转到404页面。调用后端isUSerAuth接口后,console.log(data.auth)返回true,但console.log(isloggedin)始终显示undefined,导致路由直接跳转到404,无法正常访问Profile页面。
原私有路由代码:
import React, { useEffect, useState } from "react"; import { Navigate } from "react-router-dom"; const PrivateRoutes = ({ children }) =>{ const [isloggedin, setLoggedin] = useState() const isUserAuth = async() =>{ try { const response = await fetch('http://localhost:3001/isUSerAuth',{ method: "GET", headers: { "x-access-token": localStorage.getItem("token") }, }); const data = await response.json() console.log(data.auth) if(data.auth === true){ setLoggedin(true) }else{ setLoggedin(false) } console.log(isloggedin) } catch (error) { console.log(error.message) } } useEffect(()=>{ isUserAuth() }) return ( isloggedin ? children : <Navigate to ="/404" /> ); } export default PrivateRoutes
路由配置代码:
<Route path='/profile' element={ <PrivateRoutes> <Profile /> </PrivateRoutes> } />
问题根源分析
- 初始状态与首次渲染逻辑冲突:
useState()未设置初始值,默认是undefined,组件首次渲染时直接触发Navigate跳转404,此时接口校验请求还未完成。 - setState异步特性:
setLoggedin是异步更新操作,调用后不会立刻同步修改状态值,所以紧接着的console.log(isloggedin)只能拿到旧的初始值。 - useEffect无限循环:未给
useEffect设置依赖数组,组件每次渲染都会重复调用isUserAuth,引发不必要的接口请求和状态更新。
修复方案与优化代码
import React, { useEffect, useState } from "react"; import { Navigate } from "react-router-dom"; const PrivateRoutes = ({ children }) =>{ // 用null表示"正在校验认证状态"的中间状态 const [isloggedin, setLoggedin] = useState(null) const isUserAuth = async() =>{ try { const response = await fetch('http://localhost:3001/isUSerAuth',{ method: "GET", headers: { "x-access-token": localStorage.getItem("token") }, }); const data = await response.json() // 直接根据接口返回值设置状态 setLoggedin(data.auth === true) } catch (error) { console.log(error.message) // 请求出错时默认标记为未认证 setLoggedin(false) } } // 空依赖数组确保仅组件挂载时执行一次校验 useEffect(()=>{ isUserAuth() }, []) // 监听状态变化,查看最新的认证状态 useEffect(() => { console.log("当前认证状态:", isloggedin) }, [isloggedin]) // 校验过程中显示加载提示,避免直接跳转 if (isloggedin === null) { return <div>正在验证身份...</div> } return isloggedin ? children : <Navigate to="/404" />; } export default PrivateRoutes
内容的提问来源于stack exchange,提问作者Tarek Gharbi
相关产品推荐
相关产品推荐

