在获取用户之前对路由器做出反应
2021-03-28
604
我有一个 MERN 应用程序,它使用仅 http cookies 和 jwt 作为身份验证。我在 React 中创建了一个提供程序来保存用户信息。前端也有受保护的路由。在后端,我有一个路由,如果存在 cookie,则返回当前用户,否则我将用户设置为 null。当应用程序启动、刷新或用户更改时,我会进行此调用。一切都按预期工作。
当我刷新页面或使用 URL 栏手动导航到某个页面时,就会出现问题。因为在这两种情况下,应用程序都会刷新,所以在提取完成之前,用户会在很短的时间内不存在。因此,我总是被重定向到主页,而不是我刷新或输入的页面。我尝试设置“正在加载”状态,但它只适用于应用程序组件。
示例:我在“/details/1234”上,我单击刷新,然后我被送回“/”。
有什么方法可以修复此行为吗?也许路由器中有一些变化或强制 React 在获取完成之前不执行任何操作?提前致谢。
这是我的提供程序的代码:
import { createContext, useEffect, useState } from 'react';
export const AuthContext = createContext();
function AuthContextProvider(props) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function initialUser() {
try {
const response = await fetch(`/api/users/profile`, {
headers: {
"Content-Type": "application/json"
},
method: "GET",
credentials: 'include'
});
setLoading(false);
const userData = await response.json();
return userData.message ? setUser(null) : setUser(userData)
} catch (error) {
console.log(error);
}
}
if (!user) {
initialUser();
}
}, [user]);
return (
<AuthContext.Provider value={{ user, loading, setUser }}>
{props.children}
</AuthContext.Provider>
)
}
export default AuthContextProvider
这是 App 组件的代码。App 组件由提供程序和路由器在 index.js 中包装
import { useContext } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import './App.css';
import { AuthContext } from './context/AuthContext';
import Navigation from './components/Navigation/Navigation';
import Footer from './components/Footer/Footer';
import Homescreen from './components/HomeScreen/HomeScreen';
import LandingScreen from './components/LandingScreen/LandingScreen';
import SignScreen from './components/SignScreen/SignScreen';
import Search from './components/Search/Search';
import Genres from './components/Genres/Genres';
import Details from './components/Details/Details';
import Watch from './components/Watch/Watch';
import Profile from './components/Profile/Profile';
function App() {
const { user, loading } = useContext(AuthContext);
return (
!loading
? <div className="App">
<Navigation user={user} />
<Switch>
<Route exact path="/" render={() => (!user ? <LandingScreen /> : <Homescreen />)} />
<Route path="/sign-in" render={() => (!user ? <SignScreen /> : <Redirect to="/" />)} />
<Route path="/sign-up" render={() => (!user ? <SignScreen /> : <Redirect to="/" />)} />
<Route path="/profile" render={() => (!user ? <Redirect to="/sign-in" /> : <Profile />)} />
<Route path="/search" render={() => (!user ? <Redirect to="/sign-in" /> : <Search />)} />
<Route path="/movies/:genre" render={() => (!user ? <Redirect to="/sign-in" /> : <Genres />)} />
<Route path="/details/:id" render={() => (!user ? <Redirect to="/sign-in" /> : <Details />)} />
<Route path="/watch/:id" render={() => (!user ? <Redirect to="/sign-in" /> : <Watch />)} />
</Switch>
<Footer />
</div>
: null
);
}
export default App;
1个回答
您正在更新
loading
状态为 false,
在
更新
user
状态之前。您应该先更新用户数据,
然后
更新加载状态。当您在异步 JSON 响应处理之前更新
loading
状态时,它们之间将至少有 1 个渲染周期,从而允许路由器在
user
状态尚未确定的情况下渲染路由。我建议使用
try/catch
的
finally
块,这样无论如何,当提取处理完成时,加载状态都会更新。
function AuthContextProvider(props) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function initialUser() {
try {
const response = await fetch(`/api/users/profile`, {
headers: {
"Content-Type": "application/json"
},
method: "GET",
credentials: 'include'
});
const userData = await response.json();
userData.message ? setUser(null) : setUser(userData)
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
}
if (!user) {
initialUser();
}
}, [user]);
return (
<AuthContext.Provider value={{ user, loading, setUser }}>
{props.children}
</AuthContext.Provider>
)
}
Drew Reese
2021-03-29