React useContext疑问:Login组件可访问变量,Dashboard组件却无法访问?
问题原因及解决方案
核心原因1:状态仅存于内存,页面刷新后丢失
你的LoginProvider用useState存储用户数据,这种状态只存在于内存中。登录成功后如果手动访问/dashboard或刷新页面,React会重新初始化LoginProvider,user会被重置为初始空对象{},导致Dashboard里user.name返回undefined。
核心原因2:Dashboard组件缺少空值安全校验
组件初始渲染时user是空对象,直接访问user.name会触发undefined错误,必须先判断用户数据是否存在再渲染对应内容。
额外问题:登录成功后无自动跳转逻辑
当前Login组件登录成功后没有自动跳转到Dashboard的逻辑,用户手动切换路由时容易出现状态不一致的情况。
具体修复步骤
1. 持久化用户状态到LocalStorage
修改LoginProvider,将用户数据同步到本地存储,初始化时从本地存储读取:
import React, { createContext, useState, useEffect } from "react"; import jwt_decode from 'jwt-decode'; const LoginContext = createContext(); export function LoginProvider({children}) { // 初始化时从localStorage读取用户数据 const [user, setUser] = useState(() => { const savedUser = localStorage.getItem('loginUser'); return savedUser ? JSON.parse(savedUser) : {}; }) const [isLoggedIn, setIsLoggedIn ] = useState(() => { return !!localStorage.getItem('loginUser'); }) // 监听user变化,同步到localStorage useEffect(() => { if (Object.keys(user).length > 0) { localStorage.setItem('loginUser', JSON.stringify(user)); } else { localStorage.removeItem('loginUser'); } }, [user]); function handleCallbackResponse(response){ var userData = jwt_decode(response.credential); setUser(userData); setIsLoggedIn(true); document.getElementById('signInDiv').hidden = true; // 登录成功后自动跳转到Dashboard window.location.href = '/dashboard'; } function handleSignOut(event) { setUser({}); setIsLoggedIn(false); // 补充重置登录状态 document.getElementById('signInDiv').hidden = false; // 退出后跳转到登录页 window.location.href = '/'; } return( <LoginContext.Provider value={{user, isLoggedIn, handleCallbackResponse, handleSignOut}}> {children} </LoginContext.Provider> ); } export default LoginContext
2. 给Dashboard组件添加空值保护
修改Dashboard组件,避免直接访问不存在的属性:
import React, { useContext } from 'react' import Navbar from '../organisms/Navbar' import './Dashboard.css' import LoginContext from '../LoginContext'; const Dashboard = () => { const {user} = useContext(LoginContext) return ( <div className='dashboard'> {/* 可选链+默认值,避免undefined错误 */} <h2>{user?.name || '请先登录'}</h2> <Navbar/> <div className='content'> <h1>Welcome to my Dashboard</h1> </div> </div> ) } export default Dashboard
3. 补充路由守卫(可选)
在App.js中利用isLoggedIn状态做路由拦截,未登录用户无法直接访问Dashboard:
import './App.css'; import { useContext } from 'react'; import Login from './atoms/Login'; import { BrowserRouter , Routes, Route, Navigate } from 'react-router-dom'; import Dashboard from './pages/Dashboard'; import { LoginProvider, LoginContext } from './LoginContext'; // 封装私有路由组件 const PrivateRoute = ({ children }) => { const { isLoggedIn } = useContext(LoginContext); return isLoggedIn ? children : <Navigate to="/" />; }; function App() { return ( <LoginProvider > <BrowserRouter> <Routes> <Route path="/dashboard" element={ <PrivateRoute> <Dashboard/> </PrivateRoute> }/> <Route path="/" element={<Login />} /> </Routes> </BrowserRouter> </LoginProvider> ); } export default App;
内容的提问来源于stack exchange,提问作者mateo ghidini
相关产品推荐
相关产品推荐

