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

React应用登出后未自动跳转至登录页问题求助

解决React登出后自动跳转登录页的问题

你的问题主要出在上下文未正确提供、路由未用布局组件保护、登出逻辑错误使用页面刷新这几个点上,下面是具体的修复步骤:

1. 修复ContextProvider(关键!)

你的ContextProvider没有返回StateContext.Provider,导致所有组件拿到的都是默认上下文值,状态更新根本不会触发组件重新渲染。修改后的代码:

import { createContext, useContext, useState } from "react";

const StateContext = createContext({
    user: {},
    token: null,
    notification: null,
    setUser: () => {},
    setToken: () => {},
    setNotification: () => {}
})

export const useStateContext = () => useContext(StateContext);

export const ContextProvider = ({children}) => {
    const [user, setUser] = useState({});
    const [token, _setToken] = useState(localStorage.getItem('ACCESS_TOKEN'));
    const [notification, _setNotification] = useState('');

    const setToken = (token) => {
        _setToken(token);
        if (token) {
            localStorage.setItem('ACCESS_TOKEN', token);
        } else {
            localStorage.removeItem('ACCESS_TOKEN');
        }
    };

    // 必须返回Provider,将状态和方法传递给子组件
    return (
        <StateContext.Provider
            value={{
                user,
                token,
                notification,
                setUser,
                setToken,
                setNotification: _setNotification
            }}
        >
            {children}
        </StateContext.Provider>
    );
};

2. 修复DefaultLayout的登出逻辑

去掉window.location.reload(),改用react-router的useNavigate进行跳转,并且确保状态更新在跳转之前:

import { React } from "react";
import { Navigate, Outlet, useNavigate } from "react-router-dom";
import { useStateContext } from "../contexts/ContextProvider";
import axiosClient from "../axios-client.js";
import SideBar from "./nav/SideBar";
import Header from "./nav/Header";

const DefaultLayout = () => {
    const { user, token, setUser, setToken } = useStateContext();
    const navigate = useNavigate();

    // 无token时直接跳转登录页,replace避免回退到未认证页面
    if (!token) {
        return <Navigate to="/login" replace />;
    }

    const onLogout = (ev) => {
        ev.preventDefault();

        axiosClient.post('/logout')
            .then(() => {
                // 先清空用户状态和token
                setUser({});
                setToken(null);
                // 跳转到登录页
                navigate('/login', { replace: true });
            })
            .catch(err => {
                // 即使登出请求失败,也要清空本地状态并跳转
                console.error('Logout failed:', err);
                setUser({});
                setToken(null);
                navigate('/login', { replace: true });
            });
    };

    return (
        <div className="page-wrapper">
            <SideBar />
            <div className="body-wrapper">
                <Header user={user} onLogout={onLogout} />
                {/* Outlet渲染子路由内容 */}
                <Outlet />
            </div>
        </div>
    );
};

export default DefaultLayout;

3. 重构App.js的路由结构

用布局组件区分认证路由和访客路由,确保未认证用户无法访问受保护页面:

import React from "react";
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
import DefaultLayout from './components/DefaultLayout.jsx';
import GuestLayout from './components/GuestLayout.jsx';
import Dashboard from "./views/Dashboard";
import Users from "./views/customers/Users.jsx";
import ListCustomers from "./views/customers/ListCustomers.jsx";
import Login from "./views/Login"; // 替换成你的登录组件路径

const App = () => {
    return (
        <Router>
            <Routes>
                {/* 访客路由(无需认证) */}
                <Route element={<GuestLayout />}>
                    <Route path="/login" element={<Login />} />
                </Route>

                {/* 受保护的认证路由 */}
                <Route element={<DefaultLayout />}>
                    <Route path="/" element={<Dashboard />} />
                    <Route path="users" element={<Users />}>
                        <Route path="list-customers" element={<ListCustomers />} />
                    </Route>
                </Route>

                {/* 所有未匹配的路由跳转到登录页 */}
                <Route path="*" element={<Navigate to="/login" replace />} />
            </Routes>
        </Router>
    );
};

export default App;

4. 确保根组件包裹ContextProvider

在index.js里用ContextProvider包裹App,让所有组件都能访问上下文:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { ContextProvider } from './contexts/ContextProvider';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
        <ContextProvider>
            <App />
        </ContextProvider>
    </React.StrictMode>
);

问题根源说明

  • 之前的ContextProvider没有返回Provider,导致状态更新无法触发组件重渲染,所以登出后页面不会自动检查token。
  • window.location.reload()会强制刷新页面,跳过React的状态更新和路由逻辑,而且刷新是同步操作,后面的setUser和setToken根本没机会执行。
  • App.js里直接渲染Sidebar和Header,不管用户是否认证,导致登出后这些组件依然存在,必须刷新才会重新检查token。

内容的提问来源于stack exchange,提问作者Hassan Shahzad Aheer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:54:50