如何使用 useEffect 和 Context API 来检查用户是不是登录并保护路由?

Posted

技术标签:

【中文标题】如何使用 useEffect 和 Context API 来检查用户是不是登录并保护路由?【英文标题】:How to use useEffect and the Context API to check if a user is logged in and protect a route?如何使用 useEffect 和 Context API 来检查用户是否登录并保护路由? 【发布时间】:2021-03-20 08:06:35 【问题描述】:

我正在尝试根据用户是否登录来保护路由,但我无法使其正常工作,因为似乎存储在我的上下文提供程序中的信息在初始组件加载时不可用。

我通过 useEffect 挂钩向我的节点服务器发出请求,检查用户是否在我的 App.js 文件中进行了身份验证。它尝试将此信息存储在它成功执行的上下文 api 中,但似乎渲染其他组件不会等待上下文 api “赶上”或首先加载。

我确信我遗漏了一些简单的东西,或者我使用了错误的约定来检查用户是否经过身份验证。任何帮助将不胜感激!

App.js

import React,  useState, useEffect  from 'react';
import  BrowserRouter, Switch, Route  from 'react-router-dom';
import Axios from 'axios';
import Header from './components/layout/Header';
import Home from './components/pages/Home';
import HiddenPage from './components/pages/HiddenPage';
import Login from './components/auth/Login';
import Register from './components/auth/Register';
import UserContext from './context/UserContext';
import ProtectedRoute from './components/auth/ProtectedRoute';

import './style.scss';

export default function App() 
  const [userData, setUserData] = useState(
    token: undefined,
    user: undefined,
  );

  useEffect(() => 
    const checkLoggedIn = async () => 
      let token = localStorage.getItem('auth-token');
      if (token === null) 
        localStorage.setItem('auth-token', '');
        token = '';
      
      const tokenResponse = await Axios.post(
        'http://localhost:5000/users/tokenIsValid',
        null,
         headers:  'x-auth-token': token  
      );
      if (tokenResponse.data) 
        const userResponse = await Axios.get('http://localhost:5000/users/', 
          headers:  'x-auth-token': token ,
        );
        setUserData(
          token,
          user: userResponse.data,
        );
      
    ;

    checkLoggedIn();
  , []);

  return (
    <>
      <BrowserRouter>
        <UserContext.Provider value= userData, setUserData >
          <Header />
          <div className="container">
            <Switch>
              <Route exact path="/" component=Home />
              <Route exact path="/login" component=Login />
              <Route exact path="/register" component=Register />
              <ProtectedRoute path="/hidden" component=HiddenPage />
            </Switch>
          </div>
        </UserContext.Provider>
      </BrowserRouter>
    </>
  );


ProtectedRoute.js

import React,  useContext  from 'react';
import  Redirect  from 'react-router-dom';
import UserContext from '../../context/UserContext';

export default function ProtectedRoute(props) 
  const  userData  = useContext(UserContext);
  const Component = props.component;

  const isAuthenticated = !!userData.user;
  console.log(isAuthenticated);

  return isAuthenticated ? <Component /> : <Redirect to= pathname: '/'  />;

【问题讨论】:

【参考方案1】:

添加加载状态...

const [loading, setLoading] = useState(false)

检查本地存储并进行 axios 调用后,更新状态

  if (loading) return null;

  // else render the routes

  return (
     // the regular routes...
  )

【讨论】:

【参考方案2】:

你基本上想考虑第三种状态。

要么:

    有一个user 没有user 效果尚未完成

useEffect 中的任何阶段,您都可以确认没有用户(未经身份验证)将用户设置为false

由于undefined !== false,在您的return 中您可以同时测试两者...

if (userData.user === undefined) return 'loading...'

然后您可以在知道用户具有某些价值的情况下在此行之后使用您的三元组。 false 或某个用户​​对象...

【讨论】:

以上是关于如何使用 useEffect 和 Context API 来检查用户是不是登录并保护路由?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React Hooks 和 Context API 正确地将来自 useEffect 内部调用的多个端点的数据添加到状态对象?

为啥我的组件在使用 React 的 Context API 和 useEffect 挂钩时会渲染两次?

React context API-我如何从 useEffect 钩子中分派一个动作?

在 Context.Consumer 创建的 useEffect 清理函数中取消所有订阅

如何正确使用 useEffect 与 useContext 作为依赖

React/React Context API:使用 useEffect() 钩子时等待上下文值