淺談React-router v6 實現(xiàn)登錄驗證流程
此示例演示了一個包含三個頁面的簡單登錄流程:公共頁面、受保護頁面和登錄頁面。 為了查看受保護的頁面,你必須先登錄。
首先,訪問公共頁面。 然后,訪問受保護的頁面。 你尚未登錄,因此你將被重定向到登錄頁面。 登錄后,你將被重定向回受保護的頁面。
封裝 Context 包裹容器
首先封裝AuthProvider組件,利用Context特性共享那些對于一個組件樹而言是“全局”的數(shù)據(jù)。
全局定義user、signIn、signOut數(shù)據(jù)和方法,signIn、signOut使用了高階函數(shù),也方便后續(xù)擴展和修改。
Context主要應用場景在于很多不同層級的組件需要訪問同樣一些的數(shù)據(jù)。請謹慎使用,因為這會使得組件的復用性變差。
如果你只是想避免層層傳遞一些屬性,組件組合(component composition)有時候是一個比Context更好的解決方案。
import { ReactNode, createContext, useState } from "react";
export interface AuthContextType {
user: any;
signIn: (user: string, callback: VoidFunction) => void;
signOut: (callback: VoidFunction) => void;
}
export let AuthContext = createContext<AuthContextType | null>(null);
const fakeAuthProvider = {
isAuthenticated: false,
signIn(callback: VoidFunction) {
this.isAuthenticated = true;
setTimeout(callback, 100);
},
signOut(callback: VoidFunction) {
this.isAuthenticated = false;
setTimeout(callback, 100);
},
};
const AuthProvider = ({ children }: { children: ReactNode }) => {
const [user, setUser] = useState<any>(null);
let signIn = (newUser: string, callback: VoidFunction) => {
return fakeAuthProvider.signIn(() => {
setUser(newUser);
callback();
});
};
let signOut = (callback: VoidFunction) => {
return fakeAuthProvider.signOut(() => {
setUser(null);
callback();
});
};
return (
<AuthContext.Provider value={{ user, signIn, signOut }}>
{children}
</AuthContext.Provider>
);
};
export default AuthProvider;封裝 Layout 父級容器
Layout組件主要是針對登錄狀態(tài)進行校驗,然后做相應處理。利用react-router v6中<Outlet />組件顯示嵌套路由,相比于v5版本v6實現(xiàn)嵌套路由更加方便,省略了很多冗余的判斷代碼。
import { useContext } from "react";
import { useNavigate, Link, Outlet } from "react-router-dom";
import { AuthContext, AuthContextType } from "../AuthProvider";
const useAuth = () => useContext(AuthContext);
const AuthStatus = () => {
let auth = useAuth();
let { user, signOut } = auth as AuthContextType;
let navigate = useNavigate();
if (!user) return <p>沒有登錄</p>;
return (
<>
<p>你好 {user}! </p>
<button onClick={() => signOut(() => navigate("/"))}>退出</button>
</>
);
};
const Layout = () => {
return (
<div>
<AuthStatus />
<ul>
<li>
<Link to="/">公共頁面</Link>
</li>
<li>
<Link to="/protected">受保護頁面</Link>
</li>
</ul>
<Outlet />
</div>
);
};
export default Layout;開發(fā) Login 模塊
import { useContext, FormEvent } from "react";
import { useNavigate, useLocation, Location } from "react-router-dom";
import { AuthContext, AuthContextType } from "../AuthProvider";
interface State extends Omit<Location, "state"> {
state: {
from: {
pathname: string;
};
};
}
const useAuth = () => useContext(AuthContext);
const Login = () => {
let auth = useAuth();
let { signIn } = auth as AuthContextType;
const { state } = useLocation() as State;
let from = state.from.pathname || "/";
let navigate = useNavigate();
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
let formData = new FormData(event.currentTarget);
let username = formData.get("username") as string;
signIn(username, () => navigate(from, { replace: true }));
};
return (
<div>
<p>您必須登錄才能查看該頁面 {from}</p>
<form onSubmit={handleSubmit}>
<label>
用戶名: <input name="username" type="text" />
</label>
<button type="submit">登錄</button>
</form>
</div>
);
};
export default Login;開發(fā) Protected 包裹容器
主要就是對登錄狀態(tài)進行校驗,成功則渲染子組件,否則跳轉(zhuǎn)回登錄頁面
import { useContext } from "react";
import { useLocation, Navigate } from "react-router-dom";
import { AuthContext, AuthContextType } from "../AuthProvider";
const useAuth = () => useContext(AuthContext);
const RequireAuth = ({ children }: { children: JSX.Element }) => {
let auth = useAuth();
let { user } = auth as AuthContextType;
let location = useLocation();
if (!user) return <Navigate to="/login" state={{ from: location }} replace />;
return children;
};
export default RequireAuth;App 入口文件
入口文件沒有對路由進行懶加載優(yōu)化,因為是小應用,所以實際開發(fā)還是要考慮性能優(yōu)化的。
import { Routes, Route } from "react-router-dom";
import AuthProvider from "src/views/AuthProvider";
import Layout from "src/views/auth/layout";
import LoginPage from "src/views/auth/login";
import PublicPage from "src/views/auth/publicPage";
import RequireAuth from "src/views/auth/requireAuth";
import ProtectedPage from "src/views/auth/protectedPage";
const App = () => {
return (
<AuthProvider>
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<PublicPage />} />
<Route path="/login" element={<LoginPage />} />
<Route
path="/protected"
element={
<RequireAuth>
<ProtectedPage />
</RequireAuth>
}
/>
</Route>
</Routes>
</AuthProvider>
);
};
export default App;
到此這篇關(guān)于淺談React-router v6 實現(xiàn)登錄驗證流程的文章就介紹到這了,更多相關(guān)React-router登錄驗證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
jenkins分環(huán)境部署vue/react項目的方法步驟
這篇文章主要介紹了jenkins分環(huán)境部署vue/react項目的方法,本文分步驟給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02
react?app?rewrited替代品craco使用示例
這篇文章主要為大家介紹了react?app?rewrited替代品craco使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
react-native 圓弧拖動進度條實現(xiàn)的示例代碼
本篇文章主要介紹了react-native 圓弧拖動進度條實現(xiàn)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04

