開始學習 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 Hooks 的 useRoutes,他可以獲取路由的相關資訊,所以就能做到像 vue-router 那樣把所有的路由資料寫在一起,並根據適當的路由渲染對應的元件。
往後應該也是可以自行擴充,設計路由資訊如 meta 這樣的陣列,如果有研究到這部分會再更新此文章,將資料加上。
第一次寫 react router,如果有任何想得未周到或是寫錯的地方,歡迎大家指正,感謝!