如何使用 useEffect 和 Context API 检查用户是否登录并保护路由?
How to use useEffect and the Context API to check if a user is logged in and protect a route?
我试图根据用户是否登录来保护路由,但我无法让它正常工作,因为存储在我的上下文提供程序中的信息似乎在初始组件加载时不可用。
我正在通过 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: '/' }} />;
}
添加加载状态...
const [loading, setLoading] = useState(false)
检查本地存储并进行 axios 调用后,更新状态
if (loading) return null;
// else render the routes
return (
// the regular routes...
)
你基本上想要解释第三个状态。
或者:
- 有一个
user
- 没有
user
- 效果尚未完成
在您 useEffect
的任何阶段,您都可以确认没有用户(未经身份验证)将用户设置为 false
。
自 undefined !== false
以来,在您的 return
中您可以测试两者...
if (userData.user === undefined) return 'loading...'
然后你可以在这一行之后使用你的三元组,因为你知道用户有一些价值。 false
或某个用户对象...
我试图根据用户是否登录来保护路由,但我无法让它正常工作,因为存储在我的上下文提供程序中的信息似乎在初始组件加载时不可用。
我正在通过 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: '/' }} />;
}
添加加载状态...
const [loading, setLoading] = useState(false)
检查本地存储并进行 axios 调用后,更新状态
if (loading) return null;
// else render the routes
return (
// the regular routes...
)
你基本上想要解释第三个状态。
或者:
- 有一个
user
- 没有
user
- 效果尚未完成
在您 useEffect
的任何阶段,您都可以确认没有用户(未经身份验证)将用户设置为 false
。
自 undefined !== false
以来,在您的 return
中您可以测试两者...
if (userData.user === undefined) return 'loading...'
然后你可以在这一行之后使用你的三元组,因为你知道用户有一些价值。 false
或某个用户对象...