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

React中LocalStorage的EventListener失效问题求助

问题原因

window的storage事件仅在同源的其他窗口/标签页修改localStorage时才会触发,同一页面内修改localStorage不会触发该事件。你当前是在登录页面(同一页面)存入token,所以监听的storage事件不会执行,导致App组件的token状态没有更新,自然不会自动切换到Home组件。

解决方案

方案1:登录成功后手动更新token状态

直接在登录成功的回调中更新App组件的token状态,不需要依赖storage事件。

修改App.js

将setToken作为props传递给Login组件:

import { useEffect, useState } from "react";
import "./App.css";
import Home from "./Component/Home";
import Login from "./Component/Login";
import { Routes, Route, BrowserRouter } from "react-router-dom";

function App() {
  const [token, setToken] = useState(!!localStorage.getItem('token'));

  // 保留跨标签页的storage监听(可选,用于其他标签页修改token时同步状态)
  useEffect(() => {
    const handleStorageChange = () => {
      setToken(!!localStorage.getItem('token'));
    };
    window.addEventListener('storage', handleStorageChange);
    return () => window.removeEventListener('storage', handleStorageChange);
  }, []);

  return (
    <BrowserRouter>
      <Routes>
        {token ? (
          <Route path="/" element={<Home />} />
        ) : (
          <Route path="/" element={<Login setToken={setToken} />} />
        )}
      </Routes>
    </BrowserRouter>
  );
}

export default App;

修改Login组件的登录逻辑

在登录成功后调用setToken更新状态:

const handleSubmit = (e) => {
  e.preventDefault();

  axios
    .post("AUTH_API", {
      username: username,
      password: pass,
    })
    .then((res) => {
      console.log(res.data);
      localStorage.setItem("token", res.data.token);
      setToken(true); // 手动更新App组件的token状态
    })
    .catch(function (error) {
      console.log(error);
      toast("Please Enter Valid Details!");
    });
};

方案2:使用React Context管理全局认证状态(推荐)

用Context统一管理token状态,同时处理当前页面和跨标签页的token变化,代码更易维护。

创建AuthContext.js

import { createContext, useContext, useState, useEffect } from 'react';

const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [isAuthenticated, setIsAuthenticated] = useState(!!localStorage.getItem('token'));

  // 登录:存入token并更新状态
  const login = (token) => {
    localStorage.setItem('token', token);
    setIsAuthenticated(true);
  };

  // 登出:移除token并更新状态
  const logout = () => {
    localStorage.removeItem('token');
    setIsAuthenticated(false);
  };

  // 监听跨标签页的storage变化
  useEffect(() => {
    const handleStorageChange = () => {
      setIsAuthenticated(!!localStorage.getItem('token'));
    };
    window.addEventListener('storage', handleStorageChange);
    return () => window.removeEventListener('storage', handleStorageChange);
  }, []);

  return (
    <AuthContext.Provider value={{ isAuthenticated, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  return useContext(AuthContext);
}

修改App.js

用AuthProvider包裹路由,并根据全局状态渲染组件:

import { Routes, Route, BrowserRouter } from "react-router-dom";
import { AuthProvider, useAuth } from "./AuthContext";
import Home from "./Component/Home";
import Login from "./Component/Login";

function AppContent() {
  const { isAuthenticated } = useAuth();
  return (
    <Routes>
      {isAuthenticated ? (
        <Route path="/" element={<Home />} />
      ) : (
        <Route path="/" element={<Login />} />
      )}
    </Routes>
  );
}

function App() {
  return (
    <AuthProvider>
      <BrowserRouter>
        <AppContent />
      </BrowserRouter>
    </AuthProvider>
  );
}

export default App;

修改Login组件

使用useAuth获取login方法,登录时调用:

import { useAuth } from "../AuthContext";

// ...

const { login } = useAuth();

const handleSubmit = (e) => {
  e.preventDefault();

  axios
    .post("AUTH_API", {
      username: username,
      password: pass,
    })
    .then((res) => {
      console.log(res.data);
      login(res.data.token); // 调用Context中的登录方法
    })
    .catch(function (error) {
      console.log(error);
      toast("Please Enter Valid Details!");
    });
};

方案3:优化路由跳转逻辑(可选)

更符合路由规范的写法是使用Navigate组件进行页面跳转,而不是在同一路径渲染不同组件:

import { Routes, Route, BrowserRouter, Navigate } from "react-router-dom";
// ...(结合方案1或方案2的状态管理)

function AppContent() {
  const { isAuthenticated } = useAuth();
  return (
    <Routes>
      <Route path="/login" element={<Login />} />
      <Route path="/home" element={<Home />} />
      <Route 
        path="/" 
        element={isAuthenticated ? <Navigate to="/home" /> : <Navigate to="/login" />} 
      />
    </Routes>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:02:16