反应私有路由和异步 api 调用
React private route and asynchronous api call
我需要保护我的 React 应用程序的一些路由,为此我创建了一个私有路由组件,如下所示:
import React from 'react';
import {useAuth} from "../../context/AuthContextProvider";
import {Navigate} from "react-router-dom";
import {useLocation} from "react-router";
const PrivateRoute = ({children}) => {
const {user, isAuthenticating, isAuthenticated} = useAuth();
const location = useLocation();
console.log(user, isAuthenticating, isAuthenticated);
return isAuthenticated ? children : <Navigate to="/sign-in" state={{from: location}} replace/>;
}
export default PrivateRoute;
在身份验证上下文提供程序中,我检查用户是否已登录,如下所示:
import React, {createContext, useContext, useEffect, useState} from "react";
import {useMeMutation} from "../data/user";
const AuthContext = createContext();
export const useAuth = () => useContext(AuthContext);
const AuthContextProvider = ({children}) => {
const {mutate: me} = useMeMutation();
const [auth, setAuth] = useState({
user: null,
isAuthenticating: null,
isAuthenticated: null
});
useEffect(() => {
checkAuthentication();
}, []);
const revalidate = () => {
return me({}, {
onSuccess: ({data}) => {
console.log(data);
setAuth({
user: data,
isAuthenticating: false,
isAuthenticated: true
});
},
onError: (error) => {
if ((error.response && error.response.status === 401) ||
(error.response && error.response.status === 403)) {
setAuth({
user: null,
isAuthenticating: false,
isAuthenticated: false
});
}
},
});
};
const checkAuthentication = () => {
if (auth.isAuthenticated === null) {
revalidate();
}
};
return (
<AuthContext.Provider value={{
...auth,
revalidate
}}>{children}</AuthContext.Provider>
);
};
export default AuthContextProvider;
此代码的问题是在 api 端检查用户之前显示登录组件。
我的路线是这样的:
<Routes>
<Route element={<PublicLayout/>}>
{publicRoutes.map(({component: Component, path, exact}) => (
<Route
path={`/${path}`}
key={path}
exact={exact}
element={<Component/>}
/>
))}
</Route>
<Route element={<PrivateRoute><PrivateLayout/></PrivateRoute>}>
{privateRoutes.map(({component: Component, path, exact}) => (
<Route
path={`/${path}`}
key={path}
exact={exact}
element={<Component/>}
/>
))}
</Route>
</Routes>
在私有路由组件中,我需要停止对这两个状态的渲染:
当用户第一次来到登录页面时,isAuthenticated 的值应该为null,并且当该值为false 时渲染私有路由,
当用户点击登录按钮时,我需要将 isAuthenticating 设置为 true,在这种情况下用户的状态尚不清楚,所以我还需要阻止 private 的呈现路线
const PrivateRoute = ({children}) => {
const {user, isAuthenticating, isAuthenticated} = useAuth();
const location = useLocation();
if (isAuthenticated === null || isAuthenticating === true) {
return null;
}
return isAuthenticated ? children : <Navigate to="/sign-in" state={{from: location}} replace/>;
}
并且在上下文提供程序中,我需要在调用 api 的开头指定 isAuthenticating,如下所示:
const revalidate = () => {
setAuth({
user: null,
isAuthenticating: true,
isAuthenticated: false
});
return me({}, {}
...
我需要保护我的 React 应用程序的一些路由,为此我创建了一个私有路由组件,如下所示:
import React from 'react';
import {useAuth} from "../../context/AuthContextProvider";
import {Navigate} from "react-router-dom";
import {useLocation} from "react-router";
const PrivateRoute = ({children}) => {
const {user, isAuthenticating, isAuthenticated} = useAuth();
const location = useLocation();
console.log(user, isAuthenticating, isAuthenticated);
return isAuthenticated ? children : <Navigate to="/sign-in" state={{from: location}} replace/>;
}
export default PrivateRoute;
在身份验证上下文提供程序中,我检查用户是否已登录,如下所示:
import React, {createContext, useContext, useEffect, useState} from "react";
import {useMeMutation} from "../data/user";
const AuthContext = createContext();
export const useAuth = () => useContext(AuthContext);
const AuthContextProvider = ({children}) => {
const {mutate: me} = useMeMutation();
const [auth, setAuth] = useState({
user: null,
isAuthenticating: null,
isAuthenticated: null
});
useEffect(() => {
checkAuthentication();
}, []);
const revalidate = () => {
return me({}, {
onSuccess: ({data}) => {
console.log(data);
setAuth({
user: data,
isAuthenticating: false,
isAuthenticated: true
});
},
onError: (error) => {
if ((error.response && error.response.status === 401) ||
(error.response && error.response.status === 403)) {
setAuth({
user: null,
isAuthenticating: false,
isAuthenticated: false
});
}
},
});
};
const checkAuthentication = () => {
if (auth.isAuthenticated === null) {
revalidate();
}
};
return (
<AuthContext.Provider value={{
...auth,
revalidate
}}>{children}</AuthContext.Provider>
);
};
export default AuthContextProvider;
此代码的问题是在 api 端检查用户之前显示登录组件。 我的路线是这样的:
<Routes>
<Route element={<PublicLayout/>}>
{publicRoutes.map(({component: Component, path, exact}) => (
<Route
path={`/${path}`}
key={path}
exact={exact}
element={<Component/>}
/>
))}
</Route>
<Route element={<PrivateRoute><PrivateLayout/></PrivateRoute>}>
{privateRoutes.map(({component: Component, path, exact}) => (
<Route
path={`/${path}`}
key={path}
exact={exact}
element={<Component/>}
/>
))}
</Route>
</Routes>
在私有路由组件中,我需要停止对这两个状态的渲染:
当用户第一次来到登录页面时,isAuthenticated 的值应该为null,并且当该值为false 时渲染私有路由,
当用户点击登录按钮时,我需要将 isAuthenticating 设置为 true,在这种情况下用户的状态尚不清楚,所以我还需要阻止 private 的呈现路线
const PrivateRoute = ({children}) => { const {user, isAuthenticating, isAuthenticated} = useAuth(); const location = useLocation(); if (isAuthenticated === null || isAuthenticating === true) { return null; } return isAuthenticated ? children : <Navigate to="/sign-in" state={{from: location}} replace/>; }
并且在上下文提供程序中,我需要在调用 api 的开头指定 isAuthenticating,如下所示:
const revalidate = () => {
setAuth({
user: null,
isAuthenticating: true,
isAuthenticated: false
});
return me({}, {}
...