網(wǎng)站首頁 編程語言 正文
React Router v6是React應(yīng)用程序的一個(gè)流行且功能強(qiáng)大的路由庫。它提供了一種聲明式的、基于組件的路由方法,并能處理URL參數(shù)、重定向和加載數(shù)據(jù)等常見任務(wù)。
這個(gè)最新版本的React Router引入了很多新概念,比如<Outlet />
和layout
布局路由,但相關(guān)文檔仍然很少。
本文將演示如何使用React Router v6
創(chuàng)建受保護(hù)的路由以及如何添加身份驗(yàn)證。
開始
打開終端,運(yùn)行以下命令創(chuàng)建一個(gè)新的 React 項(xiàng)目:
> npx create-react-app ReactRouterAuthDemo > cd ReactRouterAuthDemo
接下來,在 React 應(yīng)用程序中安裝 React Router
作為依賴項(xiàng):
> npm install react-router-dom
一旦 React Router 依賴項(xiàng)安裝好,我們就可以開始編輯src/index.js
文件。
首先,從 react-router-dom
中導(dǎo)入 BrowserRouter
組件,然后用<BrowserRouter />
包裹 <App />
組件,就像這樣:
import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; const rootElement = document.getElementById("root"); const root = createRoot(rootElement); root.render( <StrictMode> <BrowserRouter> <App /> </BrowserRouter> </StrictMode> );
基礎(chǔ)路由
React Router提供了 <Routes />
和 <Route />
組件,使我們能夠根據(jù)組件的當(dāng)前位置來渲染它們。
import { Routes, Route } from "react-router-dom"; import { LoginPage } from "./pages/Login"; import { HomePage } from "./pages/Home"; import "./styles.css"; export default function App() { return ( <Routes> <Route path="/" element={<HomePage />} /> <Route path="/login" element={<LoginPage />} /> </Routes> ); }
<Route />
提供了應(yīng)用程序和 React 組件之間路徑的映射。例如,當(dāng)用戶導(dǎo)航到/login
時(shí),要渲染LoginPage
組件,我們只需要像這樣提供<Route />
:
<Route path="/login" element={<LoginPage />} />
<Route />
組件可以看作是一個(gè) if
語句,只有當(dāng)元素與指定的路徑匹配時(shí),它才會(huì)作用于URL
的位置。
<Routes />
組件是 React Router v5
中的 <Switch />
組件的替代品。
我們可以通過創(chuàng)建Login.jsx
和Home.jsx
來使用 <Routes />
:
// Login.jsx export const LoginPage = () => ( <div> <h1>This is the Login Page</h1> </div> ); // Home.jsx export const HomePage = () => ( <div> <h1>This is the Home Page</h1> </div> );
接下來,我們將運(yùn)行下面的命令來啟動(dòng)應(yīng)用程序:
> npm run start
在瀏覽器中,我們默認(rèn)會(huì)看到Home
組件。如果我們使用/login
路由,我們將看到LoginPage
組件呈現(xiàn)在屏幕上。
或者,我們也可以使用一個(gè)普通的JavaScript對(duì)象,通過useRoutes
鉤子來表示應(yīng)用程序中的路由。這是一種定義路由的功能方法,其工作方式與< routes />
和<Route />
組件相同。
import { useRoutes } from "react-router-dom"; // ... export default function App() { const routes = useRoutes([ { path: "/", element: <HomePage /> }, { path: "/login", element: <LoginPage /> } ]); return routes; }
既然基本設(shè)置已經(jīng)完成,讓我們看看如何創(chuàng)建受保護(hù)的路由,從而使未經(jīng)身份驗(yàn)證的用戶無法訪問應(yīng)用程序中的某些內(nèi)容。
創(chuàng)建受保護(hù)的路由
在創(chuàng)建受保護(hù)的路由之前,讓我們先創(chuàng)建一個(gè)自定義鉤子,它將使用Context API
和useContext
鉤子處理通過身份驗(yàn)證的用戶的狀態(tài)。
import { createContext, useContext, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { useLocalStorage } from "./useLocalStorage"; const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [user, setUser] = useLocalStorage("user", null); const navigate = useNavigate(); // 驗(yàn)證用戶權(quán)限的時(shí)候,訪問該函數(shù) const login = async (data) => { setUser(data); navigate("/profile"); }; // 登出 const logout = () => { setUser(null); navigate("/", { replace: true }); }; const value = useMemo( () => ({ user, login, logout }), [user] ); return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; }; export const useAuth = () => { return useContext(AuthContext); };
上述 useAuth
鉤子中,我們暴露了用戶的狀態(tài)和一些用于用戶登錄和注銷的方法。當(dāng)用戶登出時(shí),我們使用 React Router
的 useNavigate
鉤子將他們重定向到主頁。
為了在頁面刷新時(shí)保持用戶的狀態(tài),我們將使用 useLocalStorage
鉤子,它將在瀏覽器的本地存儲(chǔ)中同步狀態(tài)值。
import { useState } from "react"; export const useLocalStorage = (keyName, defaultValue) => { const [storedValue, setStoredValue] = useState(() => { try { const value = window.localStorage.getItem(keyName); if (value) { return JSON.parse(value); } else { window.localStorage.setItem(keyName, JSON.stringify(defaultValue)); return defaultValue; } } catch (err) { return defaultValue; } }); const setValue = (newValue) => { try { window.localStorage.setItem(keyName, JSON.stringify(newValue)); } catch (err) {} setStoredValue(newValue); }; return [storedValue, setValue]; };
<ProtectedRoute />
組件將從 useAuth
鉤子中檢查當(dāng)前用戶的狀態(tài),如果用戶沒有經(jīng)過身份驗(yàn)證,則重定向到/
路徑。
import { Navigate } from "react-router-dom"; import { useAuth } from "../hooks/useAuth"; export const ProtectedRoute = ({ children }) => { const { user } = useAuth(); if (!user) { // user is not authenticated return <Navigate to="/" />; } return children; };
要重定向用戶,我們使用 <Navigate />
組件。當(dāng)父組件呈現(xiàn)當(dāng)前位置時(shí),<Navigate />
組件會(huì)改變當(dāng)前位置。它在內(nèi)部使用 usenavate
鉤子。
在 App.js
文件中,我們可以用 <ProtectedRoute />
組件包裝page
組件。例如下面,我們使用 <ProtectedRoute />
包裝<SettingsPage />
和 <ProfilePage />
組件。現(xiàn)在,當(dāng)未經(jīng)身份驗(yàn)證的用戶試圖訪問 /profile
或 /settings
路徑時(shí),他們將被重定向到主頁。
import { Routes, Route } from "react-router-dom"; import { LoginPage } from "./pages/Login"; import { HomePage } from "./pages/Home"; import { SignUpPage } from "./pages/SignUp"; import { ProfilePage } from "./pages/Profile"; import { SettingsPage } from "./pages/Settings"; import { ProtectedRoute } from "./components/ProtectedRoute"; export default function App() { return ( <Routes> <Route path="/" element={<HomePage />} /> <Route path="/login" element={<LoginPage />} /> <Route path="/register" element={<SignUpPage />} /> <Route path="/profile" element={ <ProtectedRoute> <ProfilePage /> </ProtectedRoute> } /> <Route path="/settings" element={ <ProtectedRoute> <SettingsPage /> </ProtectedRoute> } /> </Routes> ); }
如果受保護(hù)的路由數(shù)量有限,上面的方法工作得很好,但如果有多個(gè)這樣的路由,我們就必須把每個(gè)都包裝起來,這很繁瑣。
相反,我們可以使用React Router v6的嵌套路由特性,將所有受保護(hù)的路由封裝在一個(gè)布局中。
使用嵌套路由和< Outlet />
React Router v6中最強(qiáng)大的特性之一是嵌套路由。這個(gè)特性允許我們有一個(gè)包含其他子路由的路由。我們的大多數(shù)布局都與URL上的片段相耦合,React Router完全支持這一點(diǎn)。
例如,我們可以在<HomePage />
和 <LoginPage />
路由中添加一個(gè)父組件 <Route />
,就像這樣:
import { ProtectedLayout } from "./components/ProtectedLayout"; import { HomeLayout } from "./components/HomeLayout"; // ... export default function App() { return ( <Routes> <Route element={<HomeLayout />}> <Route path="/" element={<HomePage />} /> <Route path="/login" element={<LoginPage />} /> </Route> <Route path="/dashboard" element={<ProtectedLayout />}> <Route path="profile" element={<ProfilePage />} /> <Route path="settings" element={<SettingsPage />} /> </Route> </Routes> ); }
父組件 <Route />
也可以有一個(gè)路徑,它負(fù)責(zé)在屏幕上呈現(xiàn)子組件<Route />
。
當(dāng)用戶導(dǎo)航到 /dashboard/profile
時(shí),路由器將呈現(xiàn) <ProfilePage />
。為了實(shí)現(xiàn)這一點(diǎn),父路由元素必須有一個(gè) <Outlet />
組件來呈現(xiàn)子元素。Outlet
組件使嵌套的 UI 在呈現(xiàn)子路由時(shí)可見。
父路由元素還可以具有額外的公共業(yè)務(wù)邏輯和用戶界面。例如,在<ProtectedLayout />
組件中,我們已經(jīng)包含了私有路由邏輯和一個(gè)通用導(dǎo)航條,當(dāng)子路由被呈現(xiàn)時(shí),它將是可見的。
import { Navigate, Outlet } from "react-router-dom"; import { useAuth } from "../hooks/useAuth"; export const ProtectedLayout = () => { const { user } = useAuth(); if (!user) { return <Navigate to="/" />; } return ( <div> <nav> <Link to="/settings">Settings</Link> <Link to="/profile">Profile</Link> </nav> <Outlet /> </div> ) };
除了<Outlet />
組件,我們還可以選擇使用 useOutlet
鉤子,它的作用是一樣的:
import { Link, Navigate, useOutlet } from "react-router-dom"; // ... export const ProtectedLayout = () => { const { user } = useAuth(); const outlet = useOutlet(); if (!user) { return <Navigate to="/" />; } return ( <div> <nav> <Link to="/settings">Settings</Link> <Link to="/profile">Profile</Link> </nav> {outlet} </div> ); };
與受保護(hù)路由類似,我們不希望通過身份驗(yàn)證的用戶訪問 /login
路徑。讓我們?cè)?<HomeLayout />
組件中處理它:
import { Navigate, Outlet } from "react-router-dom"; import { useAuth } from "../hooks/useAuth"; export const HomeLayout = () => { const { user } = useAuth(); if (user) { return <Navigate to="/dashboard/profile" />; } return ( <div> <nav> <Link to="/">Home</Link> <Link to="/login">Login</Link> </nav> <Outlet /> </div> ) };
結(jié)尾
值得花一些時(shí)間來更好地理解 React Router v6 的工作原理,特別是用戶身份驗(yàn)證。
與以前的版本相比,React Router v6是一個(gè)巨大的改進(jìn)。它快速、穩(wěn)定、可靠。除了更容易使用之外,它還有很多新特性,比如<Outlets />
和一個(gè)改進(jìn)的<Route />
組件,這大大簡(jiǎn)化了 React 應(yīng)用中的路由。
我希望本指南對(duì)您有所幫助,希望您對(duì)如何使用React Router v6處理用戶身份驗(yàn)證有了更好的理解。
原文鏈接:https://blog.csdn.net/ImagineCode/article/details/124726400
相關(guān)推薦
- 2022-09-06 C語言模擬實(shí)現(xiàn)strstr函數(shù)的示例代碼_C 語言
- 2022-05-17 【go】解決“dial tcp 142.251.42.241:443: connect: conne
- 2022-05-24 .NET?Core剪裁器背后的技術(shù)及工作原理介紹_實(shí)用技巧
- 2022-05-04 python?與c++相互調(diào)用實(shí)現(xiàn)_python
- 2022-09-01 C++?OpenCV實(shí)戰(zhàn)之形狀識(shí)別_C 語言
- 2022-10-07 C#如何實(shí)現(xiàn)調(diào)取釘釘考勤接口的功能_C#教程
- 2022-06-21 C語言實(shí)現(xiàn)順序表的全操作詳解_C 語言
- 2022-09-04 從docker鏡像里提取dockerfile的兩種方法_docker
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支