使用React Router v6 進行身份驗證完全指南

華為雲 2022-05-14 11:32:10 阅读数:709

使用reactrouterv6身份

React Router v6是React應用程序的一個流行且功能强大的路由庫。它提供了一種聲明式的、基於組件的路由方法,並能處理URL參數、重定向和加載數據等常見任務

這個最新版本的React Router引入了很多新概念,比如<Outlet />layout布局路由,但相關文檔仍然很少。

本文將演示如何使用React Router v6創建受保護的路由以及如何添加身份驗證。

開始

打開終端,運行以下命令創建一個新的 React 項目:

> npx create-react-app ReactRouterAuthDemo> cd ReactRouterAuthDemo

接下來,在 React 應用程序中安裝 React Router 作為依賴項:

> npm install react-router-dom

一旦 React Router 依賴項安裝好,我們就可以開始編輯src/index.js文件。

首先,從 react-router-dom 中導入 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>);

基礎路由

React Router提供了 <Routes /><Route /> 組件,使我們能够根據組件的當前比特置來渲染它們。

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 />

<Route />提供了應用程序和 React 組件之間路徑的映射。例如,當用戶導航到/login時,要渲染LoginPage組件,我們只需要像這樣提供<Route />:

<Route path="/login" element={<LoginPage />} />

<Route /> 組件可以看作是一個 if 語句,只有當元素與指定的路徑匹配時,它才會作用於URL的比特置。

<Routes />

<Routes /> 組件是 React Router v5中的 <Switch /> 組件的替代品。

我們可以通過創建Login.jsxHome.jsx來使用 <Routes />

// Login.jsxexport const LoginPage = () => ( <div> <h1>This is the Login Page</h1> </div>);// Home.jsxexport const HomePage = () => ( <div> <h1>This is the Home Page</h1> </div>);

接下來,我們將運行下面的命令來啟動應用程序:

> npm run start

在瀏覽器中,我們默認會看到Home組件。如果我們使用/login路由,我們將看到LoginPage組件呈現在屏幕上。

或者,我們也可以使用一個普通的JavaScript對象,通過useRoutes鉤子來錶示應用程序中的路由。這是一種定義路由的功能方法,其工作方式與< routes /><Route />組件相同。

import { useRoutes } from "react-router-dom";// ...export default function App() { const routes = useRoutes([ { path: "/", element: <HomePage /> }, { path: "/login", element: <LoginPage /> } ]); return routes;}

既然基本設置已經完成,讓我們看看如何創建受保護的路由,從而使未經身份驗證的用戶無法訪問應用程序中的某些內容。

創建受保護的路由

在創建受保護的路由之前,讓我們先創建一個自定義鉤子,它將使用Context APIuseContext鉤子處理通過身份驗證的用戶的狀態。

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(); // 驗證用戶權限的時候,訪問該函數 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 鉤子中,我們暴露了用戶的狀態和一些用於用戶登錄和注銷的方法。當用戶登出時,我們使用 React RouteruseNavigate 鉤子將他們重定向到主頁。

為了在頁面刷新時保持用戶的狀態,我們將使用 useLocalStorage 鉤子,它將在瀏覽器的本地存儲中同步狀態值。

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 鉤子中檢查當前用戶的狀態,如果用戶沒有經過身份驗證,則重定向到/路徑。

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 /> 組件。當父組件呈現當前比特置時,<Navigate /> 組件會改變當前比特置。它在內部使用 usenavate 鉤子。

App.js 文件中,我們可以用 <ProtectedRoute /> 組件包裝page 組件。例如下面,我們使用 <ProtectedRoute /> 包裝<SettingsPage /><ProfilePage /> 組件。現在,當未經身份驗證的用戶試圖訪問 /profile/settings 路徑時,他們將被重定向到主頁。

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> );}

如果受保護的路由數量有限,上面的方法工作得很好,但如果有多個這樣的路由,我們就必須把每個都包裝起來,這很繁瑣。

相反,我們可以使用React Router v6的嵌套路由特性將所有受保護的路由封裝在一個布局中。

使用嵌套路由和< Outlet />

React Router v6中最强大的特性之一是嵌套路由。這個特性允許我們有一個包含其他子路由的路由。我們的大多數布局都與URL上的片段相耦合,React Router完全支持這一點。

例如,我們可以在<HomePage /><LoginPage /> 路由中添加一個父組件 <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 /> 也可以有一個路徑,它負責在屏幕上呈現子組件<Route />

當用戶導航到 /dashboard/profile 時,路由器將呈現 <ProfilePage />。為了實現這一點,父路由元素必須有一個 <Outlet /> 組件來呈現子元素。Outlet 組件使嵌套的 UI 在呈現子路由時可見。

父路由元素還可以具有額外的公共業務邏輯和用戶界面。例如,在<ProtectedLayout /> 組件中,我們已經包含了私有路由邏輯和一個通用導航條,當子路由被呈現時,它將是可見的。

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> );};

與受保護路由類似,我們不希望通過身份驗證的用戶訪問 /login 路徑。讓我們在 <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> )};

結尾

值得花一些時間來更好地理解 React Router v6 的工作原理,特別是用戶身份驗證。

與以前的版本相比,React Router v6是一個巨大的改進。它快速、穩定、可靠。除了更容易使用之外,它還有很多新特性,比如<Outlets />和一個改進的<Route />組件,這大大簡化了 React 應用中的路由。

我希望本指南對您有所幫助,希望您對如何使用React Router v6處理用戶身份驗證有了更好的理解。

版权声明:本文为[華為雲]所创,转载请带上原文链接,感谢。 https://qdmana.com/2022/134/202205141131101369.html