Copyright © 2008 ~ 2024 MUKI space* / omegaBook theme All Rights Reserved.

開始學習 React 的第一步,就是在路由上栽了個跟頭 XD。

相較於 Vue,React 要自己處理的東西比較多,也必須要更了解底層的邏輯,所以這次也透過學習 React Hook,把跟 Vue 類似功能的 router-view, 導航守衛 ... 等等串在一起。

功能介紹

這是一個後台網站,我預計達到以下功能:

狀態:未登入

  • 不管輸入什麼網址,都會跳轉到 /login

狀態:登入

  • 登入後網址會跳轉到 /
  • 顯示固定的元件(如 <Nav />,或俗稱的天地 <Header />, <Footer />),但是登入頁不會有這些元件
  • 輸入不同的網址,會根據 routes 的 element 渲染出不同的元件
  • 可以配置子路由
  • 如果輸入了 /login,會跳轉回首頁

建立導航守衛

我建立了兩個檔案,做到類似導航守衛的功能:

▼ PublicRoute.tsx:

import React from 'react'
import { Navigate } from 'react-router-dom'

const PublicRoute = ({ children }: any) => {
  const token = localStorage.getItem('token')
  // 登入情況下,如果輸入了 /login,會跳轉回首頁
  if (token) return <Navigate to='/' replace />
  return children
}

export default PublicRoute

▼ ProtectedRoute.tsx:

import React from 'react'
import { Navigate } from 'react-router-dom'

const ProtectedRoute = ({ children, redirectPath = '/login' }: any) => {
  const token = localStorage.getItem('token')
  // 未登入情況下,會跳轉回 /login 頁面
  if (!token) return <Navigate to={redirectPath} replace />
  return children
}

export default ProtectedRoute

建立路由資料

就像在 vue router 建立 routers.ts 檔案一樣,我在 react 建立了一份 Routes.tsx 檔案,放置所有路由的資訊

▼ Routes.tsx:

import React from 'react'
import { Outlet, Navigate } from 'react-router-dom'

import PublicRoute from './PublicRoute'
import ProtectedRoute from './ProtectedRoute'

import HomePage from './pages/HomePage'
import ReservationPage from './pages/ReservationPage'
import CreateReservationPage from './pages/CreateReservationPage'
import EditReservationPage from './pages/EditReservationPage'
import LoginPage from './pages/LoginPage'

export const Routes = [
  {
    path: '/',
    // 將所有需要保護的路由,用 <ProtectedRoute> 包起來
    element: <ProtectedRoute><HomePage /></ProtectedRoute>,
  },
  {
    path: '/reservation',
    name: 'reservation',
    // <Outlet /> 可以渲染子路由的元件
    element: <ProtectedRoute><Outlet /></ProtectedRoute>,
    children: [
      {
        path: '',
        element: <ReservationPage />,
      },
      {
        path: 'create',
        name: 'createReservation',
        element: <CreateReservationPage />,
      },
      {
        path: 'edit/:id',
        name: 'editReservation',
        element: <EditReservationPage />
      }
    ]
  },
  {
    path: '/login',
    name: 'login',
    // 不需要保護的路由,用 <PublicRoute> 包起來
    element: <PublicRoute><LoginPage /></PublicRoute>
  },
  {
    path: '*',
    // 未匹配的網址一律導回首頁
    element: <Navigate to="/" replace />,
  },
]

渲染資料

最後在 App.tsx,渲染路由元件

import { useRoutes, Link } from 'react-router-dom'
import { Routes } from './Routes'

const App = () => {
  const token = localStorage.getItem('token')
  const routing = useRoutes(Routes)

  return (
    <div>
      {/* 如果有 token 就顯示 <Navbar />元件 */}
      {token && <Navbar />}
      {routing}
    </div>
  )
}

const Navbar = () => {
  return (
    <div>
      <nav>
        <ul>
          <Link to="/">Home</Link>
          <Link to="/reservation">Reservation</Link>
        </ul>
      </nav>
    </div>
  )
}

export default App

參考資料

[筆記] 透過 React Router 實作路由保護機制

後記

我們用的是 React Hooks 的 useRoutes,他可以獲取路由的相關資訊,所以就能做到像 vue-router 那樣把所有的路由資料寫在一起,並根據適當的路由渲染對應的元件。

往後應該也是可以自行擴充,設計路由資訊如 meta 這樣的陣列,如果有研究到這部分會再更新此文章,將資料加上。

第一次寫 react router,如果有任何想得未周到或是寫錯的地方,歡迎大家指正,感謝!

歡迎給我點鼓勵,讓我知道你來過 :)

16
Subscribe
Notify of
guest

0 則留言
Inline Feedbacks
View all comments