MUKI AI Summary
學習 React 路由時,需自行處理更多細節,並了解底層邏輯。利用 React Hook 將類似 Vue 的功能串聯,如 router-view 和導航守衛。未登入時,所有網址跳轉至 /login;登入後顯示固定元件,並根據不同網址渲染對應元件。建立 PublicRoute 和 ProtectedRoute 來實現導航守衛,並在 Routes.tsx 中配置路由。最後在 App.tsx 渲染路由元件,根據 token 顯示 Navbar。...
開始學習 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,如果有任何想得未周到或是寫錯的地方,歡迎大家指正,感謝!