在做前端的時候,都會碰到多個頁面切換的畫面,而透過React Router這個套件,就能簡單的管理跳轉頁面的問題
內容目錄
SPA跟SSR的比較表
SPA切換頁面需要像伺服器請求,並且會轉換網址,尤其剛開始拿到的是空白頁面,對使用者體驗差,google爬蟲抓取資料不易,對SEO排名有影響,但相對就不用兼顧伺服器部分,開發成本低
SPA單頁應用 | SSR伺服器渲染 | |
伺服器負擔 | 大 | 小 |
使用者體驗 | 差 | 佳 |
SEO排名 | 較差 | 較好 |
HTML | 一開始空白 | 對應頁面的內容 |
開發成本 | 較低 | 較高 |
Router安裝
先來到官網,並且點選Read the Docs,並到左邊有個GTTING STARTER裡面的Installation。選好之後頁面的Basic Installation有npm安裝的指令
npm install react-router-dom@6


引入套件
剛剛的安裝頁面繼續往下找,有一個Create React App,在這裡面有import的程式碼,以及將你要有路由的組件用< BrowserRouter>包覆起來
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);

繼續往下移,可以看到app.jsx要改的內容
先將react-router-dom給import進來,分別為Routes, Route, Link
- Routes是有很多Route的時候,要用來包覆這些路由的外層,是依附在BrowserRouter底下的
- Route的用法就是你要的路徑(path),對應要轉換的組件element
import * as React from "react";
import { Routes, Route, Link } from "react-router-dom";
import "./App.css";
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />} />
</Routes>
</div>
);
}

接下來就是把home跟about組件加入進去,也在網頁裡往下移都有範例
這裡面用到link跟<a href>差不多,只是不用在刷新頁面的情況下,去切換頁面
// App.js
function Home() {
return (
<>
<main>
<h2>Welcome to the homepage!</h2>
<p>You can do this, I believe in you.</p>
</main>
<nav>
<Link to="/about">About</Link>
</nav>
</>
);
}
function About() {
return (
<>
<main>
<h2>Who are we?</h2>
<p>That feels like an existential question, don't you think?</p>
</main>
<nav>
<Link to="/">Home</Link>
</nav>
</>
);
}

顯示多個路徑
選到官網的GTTING STARTER裡面的Tutorial。Nested Routes裡面就是在教怎麼放多個路徑,把Route 改成<Route> </ Route>,包裹住要加入的頁面組件

另外從原本的組件修改,在about加main
- 建立一個main組件
- 放入about的Route裡面
- 將outlet給import進來
- 在about裡面使用
import { Routes, Route, Link, Outlet } from "react-router-dom";
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />}>
<Route path="main" element={<Main />} />
</Route>
</Routes>
</div>
);
}
function Main() {
return (
<>
<p>main標籤</p>
</>
);
}
function About() {
return (
<>
<main>
<h2>Who are we?</h2>
<p>That feels like an existential question, don't you think?</p>
</main>
<nav>
<Link to="/">Home</Link>
</nav>
<Outlet />
</>
);
}
改成動態的路由
這邊改成放入:Item,也就是在about後面不管接什麼,都會引導到Item這個頁面,通常是用在放用戶ID或是有好幾個頁面
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />}>
<Route path=":Item" element={<Item />} />
</Route>
</Routes>
</div>
);
}
function Item() {
return (
<>
<p>main標籤</p>
</>
);
}
抓取Url
在官網的Reading URL Params中有提到一個hook { useParams },可以用他來抓取

在剛剛的範例中把useParams給import進來
使用這個useParams()把Url抓下來
import { Routes, Route, Link, Outlet, useParams } from "react-router-dom";
function Item() {
const url = useParams();
console.log("url", url);
return (
<>
<p>main標籤</p>
</>
);
}

HTML元件加上跳轉
看到官網的Navigating Programmatically

在拿剛剛的範例來改,把link改成button之後,透過useNavigate,改成可以跳轉頁面的功能
- 先將useNavigate給import進來
- 再將useNavigate()實作出來
- 並使用點擊事件引入切換頁面功能
import { Routes, Route, Link, Outlet, useParams, useNavigate,
} from "react-router-dom";
function Home() {
let navigate = useNavigate();
return (
<>
<main>
<h2>Welcome to the homepage!</h2>
<p>You can do this, I believe in you.</p>
</main>
<nav>
{/* <Link to="/about">About</Link> */}
<button
onClick={() => {
navigate("/about");
}}
>
about
</button>
</nav>
</>
);
}

使用config的寫法
在官網的Route Objects可以找到範例,那就是把他整理成json的格式,這樣將來要引入到別的地方也比較方便操作

那繼續拿剛剛的範例
- 把useRoutes跟RouteObject給import進來
- 把RouteObject當作一個陣列型態
- 組成方式最外面為陣列,每一個Route為一個物件{ },要有path跟element
- path放入路徑、element放組件
- 而有子路徑的放children,children的組成也是一個陣列在外,裡面繼續包Route為一個物件{}
- 最後將 RouteObject宣告的內容用useRoutes實作出來
- 最後放入return渲染出來就OK囉
import { Routes, Route, Link, Outlet, useParams, useNavigate, RouteObject, useRoutes,} from "react-router-dom";
let routerConfig: RouteObject[] = [
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
children: [
{
path: "/about:Item",
element: <Item />,
},
],
},
];
function App() {
const elements = useRoutes(routerConfig);
return (
<div className="App">
<h1>Welcome to React Router!</h1>
{/* <Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />}>
<Route path=":Item" element={<Item />} />
</Route>
</Routes> */}
{elements}
</div>
);
}
切換沒有設定的頁面
那當網址打錯得時候,可以預設一個沒有的頁面給他
- 設定一個NoMatch的組件
- 然後加入到剛剛設定的routerConfig
- 在下面再新增一個route的物件,path為*,組件就是NoMatch
const NoMatch: React.FC = () => {
return (
<>
<p>沒有此頁面</p>
</>
);
};
let routerConfig: RouteObject[] = [
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
children: [
{
path: "/about:Item",
element: <Item />,
},
],
},
{
path: "*",
element: <NoMatch />,
},
];

Webpack Server取得跳轉功能
2023/3/17更新
研究原因
以上範例都是用npx create-react-app my-app的專案所做的練習,後續為了更深入研究React,我研究了Webpack從0建置及加入TypeScript跟React跟React Router
解決的問題
從頭開始建置的專案,在啟動Webpack Server,會遇到輸入網址無法跳轉的問題,這時候要在webpack.config.js做一點修改
- devServer新增historyApiFallback: true,
- 利用HTML5 History API來實現路由跳轉,訪問一個不存在路由時,會跳轉到指令頁面
- 在outpur新增publicPath: ‘/’
- output.publicPath是”/”時,表示根路徑是”/”,這樣使用react-router-dom可以正確地加載
module.exports = {
output: {
publicPath: '/',
},
devServer: {
historyApiFallback: true,
},
};
結論
今天持續學習布魯斯的 TypeScript + React 全攻略|快速上手仿 Instagram UI,在課程中布魯斯詳細的講解SPA跟SSR的運作邏輯,而伺服器渲染的方式對於一個開始懂得管理資源,控制開發流程及注重效能來說,是非常重要的觀念,所以很開心在學習React Router之餘,還有學習到這些觀念
而後面也針對Router真的在上傳到server時,所遇到的問題及解決的觀念,讓我覺得非常值得,畢竟花時間都不一定查的到這些bug的原因,讓我以後可以直接避掉雷坑
那至於React Router本身的學習應用並不是相當困難,但確實很重要的觀念,我們在拿到陌生專案的時候,第一個可以先打開的檔案,就是router的config,去看看整個程式的頁面架構長什麼樣子,減少我們探索的時間
