React中用localStorage存登录状态 如何全局响应登录登出变更
问题原因分析
localStorage不是 React 响应式状态,直接把它加到 useEffect 依赖数组不会触发重渲染,你写的第二个监听localStorage的useEffect完全不会按预期执行- 第一个初始化useEffect依赖为空数组,仅会在组件首次挂载时执行一次,后续登录/登出操作修改
localStorage后不会重新执行更新状态 handleLogout方法中你注释了移除token的代码,而且登录操作触发时没有通知导航栏组件更新状态的机制localStorage.getItem本身是同步方法,不需要加async/await调用,属于冗余逻辑
修复方案
方案1:监听自定义事件 + 封装鉴权方法(无需引入额外状态管理,改造成本最低)
首先修改AuthAPI.js,封装统一的登录/登出方法,操作存储的同时触发状态变更通知:
// AuthAPI.js 完整代码 // 登录成功后调用,写入token并通知状态变更 export const login = (token) => { localStorage.setItem("token", token); window.dispatchEvent(new Event("authStateChange")); }; // 登出时调用,清除token并通知状态变更 export const logout = () => { localStorage.removeItem("token"); window.dispatchEvent(new Event("authStateChange")); }; // 原有判断登录状态的方法保留 export const isLoggedIn = () => { const token = localStorage.getItem("token"); return !!token; };
然后修改NavLinks.js,监听登录状态变更事件,修正业务逻辑:
import React, { useEffect, useState } from "react"; import { NavLink } from "react-router-dom"; import { isLoggedIn, logout } from "../APIHandler/AuthAPI"; import styles from "./NavLinks.module.css"; export default function NavLinks() { // 初始化直接调用封装好的isLoggedIn方法获取状态 const [isLoggedInState, setIsLoggedInState] = useState(isLoggedIn()); // 统一更新登录状态的方法 const updateAuthState = () => { setIsLoggedInState(isLoggedIn()); }; useEffect(() => { // 监听鉴权状态变更事件 window.addEventListener("authStateChange", updateAuthState); // 可选:监听storage事件实现多标签页登录状态同步 window.addEventListener("storage", updateAuthState); // 组件卸载时移除监听避免内存泄漏 return () => { window.removeEventListener("authStateChange", updateAuthState); window.removeEventListener("storage", updateAuthState); }; }, []); const handleLogout = (e) => { e.preventDefault(); // 调用封装好的登出方法,自动触发状态更新 logout(); }; return ( <> <li className={styles.main_nav__item}> <NavLink to="/">HOME</NavLink> </li> <li className={styles.main_nav__item}> <NavLink to="/blogs">BLOGS</NavLink> </li> {!isLoggedInState && ( <li className={styles.main_nav__item}> <NavLink to="/login">LOGIN</NavLink> </li> )} {isLoggedInState && ( <li className={styles.main_nav__item}> <button onClick={handleLogout} className={styles.logout}> LOGOUT </button> </li> )} </> ); }
最后注意:登录页的登录成功逻辑中,不要直接调用localStorage.setItem写入token,要调用封装好的login(token)方法,才能触发事件通知导航栏同步状态。
方案2:React Context全局状态管理(适合中大型项目)
如果项目有多处需要用到登录状态,推荐用React Context把鉴权状态提升到全局,所有组件可以直接访问、修改状态,不需要手动派发事件。
内容的提问来源于stack exchange,提问作者Rohan Devaki
相关产品推荐
相关产品推荐

