React 应用程序在注销时不会重定向到登录页面

问题描述 投票:0回答:1

我正在开发一个带有用户身份验证的 React 应用程序。我想在用户注销时(即,当他们的身份验证令牌被删除时)自动将用户重定向到登录页面。但是,在我手动刷新页面之前,应用程序不会重定向。

这是我的代码的相关部分:

默认布局.jsx:

import {React, useEffect} 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, isAuthenticated, setUser, setToken } = useStateContext();

    if (!token) {
        return <Navigate to="/login" />;
    }

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

        axiosClient.post('/logout')
            .then(() => {
                window.location.reload()
                setUser({})
                setToken(null)
            })
    }

   
};

ContextProvider:

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

const StateContext = createContext({
    currentUser: null,
    token: null,
    notification: null,

    setUser: () => {},
    setToken: () => {},
    setNotification: () => {}
})

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

    const [notification, _setNotification] = useState('');

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

        } else {
            localStorage.removeItem('ACCESS_TOKEN');
        }
    }

}

App.js:

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Sidebar from "./components/nav/SideBar.jsx";
import Header from "./components/nav/Header.jsx";
import Dashboard from "./views/Dashboard";
import GuestLayout from './components/GuestLayout.jsx'
import { useStateContext } from "./contexts/ContextProvider";
import Users from "./views/customers/Users.jsx";
import ListCustomers from "./views/customers/ListCustomers.jsx";
import {Outlet} from "react-router-dom";

const App = () => {

    return (
        <Router>
            <div className="page-wrapper">
                <Sidebar />
                <div className="body-wrapper">
                    <Header />
                    <Routes>
                        <Route path="/" element={<Dashboard />} />
                        <Route path="users" element={<Users />}>
                            <Route index element={<Outlet />}>
                                <Route path="list-customers" element={<ListCustomers />} />
                            </Route>
                        </Route>

                    </Routes>
                </div>
            </div>
        </Router>
    );
};

标头组件中的注销按钮:

import React, {useEffect} from "react";

export default function Header({ user, onLogout }) {

    return (
        <header className="app-header">
            <nav className="navbar navbar-expand-lg navbar-light">
                <ul className="navbar-nav">
                    <li className="nav-item d-block d-xl-none">
                        <a className="nav-link sidebartoggler nav-icon-hover" id="headerCollapse" href="javascript:void(0)">
                            <i className="ti ti-menu-2"></i>
                        </a>
                    </li>
                    <li className="nav-item">
                        <a className="nav-link nav-icon-hover" href="javascript:void(0)">
                            <i className="ti ti-bell-ringing"></i>
                            <div className="notification bg-primary rounded-circle"></div>
                        </a>
                    </li>
                </ul>
                {user.name} &nbsp; &nbsp;
                <button onClick={onLogout} className="btn btn-primary">Logout</button>
                
            </nav>
        </header>
    );
}

我尝试了多种解决方案,包括使用

setToken
的回调,将导航逻辑移至
setToken
中的
ContextProvider
函数中,以及在
App.js
文件中添加条件以渲染
DefaultLayout
组件仅当用户通过身份验证时。然而,这些解决方案要么不起作用,要么导致刷新无限循环。

我是一名初学者,我正在按照 YouTube 教程构建这个项目。我不确定为什么相同的代码在其他应用程序中有效,但在我的应用程序中无效。任何帮助将不胜感激。

谢谢!

我尝试通过建议不同的方法来解决这个问题。我期望这些解决方案之一能够解决问题,并且当身份验证令牌被删除时,应用程序会自动重定向到登录页面。然而,尽管尝试了多种解决方案,问题仍然存在。应用程序不会在注销后立即重定向到登录页面,而是需要刷新手动页面。在某些情况下,建议的解决方案会导致无限循环的刷新。这不是预期的结果,我目前正在寻找此问题的替代解决方案。

reactjs react-router
1个回答
0
投票

我怀疑正是这个

window.location.reload()
中断了从localStorage中清除令牌,因此当页面重新加载时,之前存储的任何值都会保留。我怀疑您还在其他地方添加了一些额外的逻辑,当应用程序安装时由于重新加载而验证令牌,然后由于令牌已失效而起作用。

我建议删除

window.location.reload()
,以便应用程序保持安装状态,并将重定向逻辑移至注销处理程序中。我建议还将身份验证逻辑集中到上下文提供程序中。

示例:

const StateContext = createContext({
  currentUser: null,
  token: null,
  notification: null,

  setUser: () => {},
  setToken: () => {},
  setNotification: () => {},
  logout: () => {},
})

export const ContextProvider = ({ children }) => {
  const navigate = useNavigate();

  const [user, setUser] = useState(null);
  const [token, setToken] = useState(() => {
    return JSON.parse(localStorage.getItem('ACCESS_TOKEN'));
  });

  const [notification, _setNotification] = useState(null);

  useEffect(() => {
    if (token) {
      localStorage.setItem('ACCESS_TOKEN', JSON.stringify(token));
    } else {
      localStorage.removeItem('ACCESS_TOKEN');
    }
  }, [token]);

  const logoutHandler = () => {
    axiosClient.post('/logout')
      .then(() => {
        setUser(null);
        setToken(null);
      })
      .then(() => {
        navigate("/login", { replace: true });
      })
      .catch(error => {
        // catch/handle any thrown errors or Promise rejections
      });
  };

  ...

  const value = {
    currentUser,
    token,
    notification,
    setUser,
    setToken,
    setNotification,
    logout,
  };

  return (
    <StateContext.Provider value={value}>
      {children}
    </StateContext>
  );
}
const DefaultLayout = () => {
  const {
    user,
    token,
    isAuthenticated,
    logout,
  } = useStateContext();

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

    logout();
  }

  ... 
};
© www.soinside.com 2019 - 2024. All rights reserved.