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

React Router Dom V6无Token时重定向登录页不生效如何解决

React Router V6 Token不存在/登出时重定向登录页实现

问题根源

判断逻辑不生效核心原因有3个:

  • 组件渲染阶段直接调用navigate()属于违规副作用:React要求渲染过程必须是纯函数,导航、状态更新这类副作用不能直接写在组件函数的同步执行流里,会触发渲染冲突警告,直接导致导航逻辑失效。
  • 缺少token状态监听:现有判断只在组件首次加载时执行一次,后续如果token被清除/过期,组件不会重新触发校验逻辑。
  • 未覆盖token无效场景:本地存储的token可能是过期、伪造的,就算存在也可能鉴权失败,现有逻辑没有处理接口返回401的情况。

可直接用的实现代码

方式1:单组件修复(快速改现有代码)

把校验逻辑移到useEffect中,同时增加接口鉴权失败的跳转处理:

import React,{useState,useEffect} from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';

const Home = () => {
  const [user,setUser]=useState(null);
  const navigate = useNavigate();

  const getUser=async()=>{
    // 先判断本地有没有token,没有直接跳
    const token = localStorage.getItem('token');
    if(!token){
      navigate("/login", { replace: true });
      return;
    }
    try {
      const res=await axios.get("/auth",{
        headers:{
          Authorization: `Bearer ${token}`,
        },
      });
      setUser(res.data);
    } catch (err) {
      // 接口返回401/403说明token无效,清缓存跳登录
      if(err.response?.status === 401 || err.response?.status === 403){
        localStorage.removeItem("token");
        navigate("/login", { replace: true });
      }
    }
  };

  useEffect(()=>{
    getUser();
    // 监听storage变化,其他标签页登出/清token时当前页也能自动跳转
    const handleStorageChange = () => {
      if(!localStorage.getItem("token")){
        navigate("/login", { replace: true });
      }
    }
    window.addEventListener('storage', handleStorageChange);
    return () => window.removeEventListener('storage', handleStorageChange);
  },[navigate]);

  const logout=()=>{
    localStorage.removeItem("token");
    // replace: true 替换历史记录,避免用户点返回又回到需要鉴权的页面
    navigate("/login", { replace: true });
  };
  
  return (
    <div className="m-5">
      <div className="jumbotron">
        <p className="lead">Welcome {user && user.name}</p>
        <button className="btn btn-danger" onClick={logout}>Logout</button>
      </div>
    </div>
  )
}

export default Home

方式2:全局路由守卫(推荐,所有鉴权页面通用)

不用每个页面都重复写校验逻辑,封装一个受保护路由组件,在路由配置层统一拦截:

  1. 先封装RequireAuth组件
import { Navigate, useLocation } from 'react-router-dom';

const RequireAuth = ({ children }) => {
  const location = useLocation();
  const token = localStorage.getItem('token');
  // 没token直接跳登录,记录当前来源页,登录后可以跳回来
  if(!token){
    return <Navigate to="/login" state={{ from: location }} replace />
  }
  // 有token直接渲染对应页面
  return children;
}

export default RequireAuth;
  1. 在路由配置里包裹需要鉴权的页面
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './Home';
import Login from './Login';
import RequireAuth from './RequireAuth';

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<Login />} />
        {/* 所有需要登录才能进的页面都包在RequireAuth里 */}
        <Route path="/" element={
          <RequireAuth>
            <Home />
          </RequireAuth>
        } />
        {/* 其他受保护路由照这个格式加即可 */}
      </Routes>
    </BrowserRouter>
  )
}

注意:全局守卫只做本地token存在性校验,接口401的跳转逻辑建议统一放到axios拦截器里处理,不用每个接口单独写。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:09:19