首頁 > 軟體

使用React Router v6 新增身份驗證的方法

2022-05-31 22:00:20

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 />提供了應用程式和 React 元件之間路徑的對映。例如,當用戶導航到/login時,要渲染LoginPage元件,我們只需要像這樣提供<Route />:

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

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

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

我們可以通過建立Login.jsxHome.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>
);

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

> 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處理使用者身份驗證有了更好的理解。

到此這篇關於使用React Router v6 進行身份驗證完全指南的文章就介紹到這了,更多相關React Router v6驗證內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com