淺談React-router v6 實現(xiàn)登錄驗證流程
此示例演示了一個包含三個頁面的簡單登錄流程:公共頁面、受保護(hù)頁面和登錄頁面。 為了查看受保護(hù)的頁面,你必須先登錄。
首先,訪問公共頁面。 然后,訪問受保護(hù)的頁面。 你尚未登錄,因此你將被重定向到登錄頁面。 登錄后,你將被重定向回受保護(hù)的頁面。
封裝 Context 包裹容器
首先封裝AuthProvider
組件,利用Context
特性共享那些對于一個組件樹而言是“全局”的數(shù)據(jù)。
全局定義user
、signIn
、signOut
數(shù)據(jù)和方法,signIn
、signOut
使用了高階函數(shù),也方便后續(xù)擴(kuò)展和修改。
Context
主要應(yīng)用場景在于很多不同層級的組件需要訪問同樣一些的數(shù)據(jù)。請謹(jǐn)慎使用,因為這會使得組件的復(fù)用性變差。
如果你只是想避免層層傳遞一些屬性,組件組合(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)進(jìn)行校驗,然后做相應(yīng)處理。利用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">受保護(hù)頁面</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)進(jìn)行校驗,成功則渲染子組件,否則跳轉(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 入口文件
入口文件沒有對路由進(jìn)行懶加載優(yōu)化,因為是小應(yīng)用,所以實際開發(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項目的方法,本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02react?app?rewrited替代品craco使用示例
這篇文章主要為大家介紹了react?app?rewrited替代品craco使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11react-routerV6版本和V5版本的詳細(xì)對比
React-Router5是React-Router6的前一個版本,它已經(jīng)被React-Router6取代,React-Router 6是一次較大的重大更新,本文就來介紹一下react-routerV6版本和V5版本的詳細(xì)對比,感興趣的可以了解一下2023-12-12react-native 圓弧拖動進(jìn)度條實現(xiàn)的示例代碼
本篇文章主要介紹了react-native 圓弧拖動進(jìn)度條實現(xiàn)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04教你應(yīng)用?SOLID?原則整理?React?代碼之單一原則
這篇文章主要介紹了如何應(yīng)用?SOLID?原則整理?React?代碼之單一原則,今天,我們將從一個糟糕的代碼示例開始,應(yīng)用 SOLID 的第一個原則,看看它如何幫助我們編寫小巧、漂亮、干凈的并明確責(zé)任的 React 組件,需要的朋友可以參考下2022-07-07