測驗:React Router 快速入門
共 5 題,點選答案後會立即顯示結果
1. 什麼是 SPA(單頁應用程式)的核心特性?
2. 在 React Router 中,為什麼應該使用 <Link> 而不是 <a> 標籤來建立導覽連結?
3. 以下哪個元件必須包住整個 App,才能讓應用程式使用 React Router 的路由功能?
4. 在以下程式碼中,當網址是 /about 時,會顯示什麼?
<Routes>
<Route path=”/” element={<Home />} />
<Route path=”/about” element={<About />} />
<Route path=”*” element={<NotFound />} />
</Routes>
5. 前端路由是透過什麼瀏覽器 API 來改變網址列但不重新載入頁面?
一句話說明
前端路由讓單頁應用程式(SPA)可以切換頁面,但不用重新載入整個網頁。
這篇文章會教你什麼
讀完這篇,你會看懂:
- SPA 和傳統網站的差別
- 為什麼需要前端路由
- React Router 的基本設定長什麼樣
- 當 AI 幫你建立路由時,你知道它在幹嘛
先搞懂:SPA 是什麼?
傳統多頁面網站
用戶點擊連結
↓
瀏覽器向伺服器請求新頁面
↓
伺服器回傳完整 HTML
↓
整個頁面重新載入(白畫面閃一下)
單頁應用程式(SPA)
用戶點擊連結
↓
JavaScript 攔截點擊
↓
只更新需要變動的部分
↓
網址改變,但頁面不重載(超順暢)
一句話:SPA 就是「整個網站只有一個 HTML 檔,用 JavaScript 來切換畫面內容」。
前端路由 vs 後端路由
| 特性 | 後端路由 | 前端路由 |
|---|---|---|
| 處理位置 | 伺服器 | 瀏覽器 |
| 切換速度 | 慢(需要網路請求) | 快(本地切換) |
| 頁面載入 | 整頁重載 | 局部更新 |
| 網址變化 | 真的換頁 | 假的換頁(History API) |
翻譯:
- 後端路由:「你要 /about 頁面?我去伺服器拿一個新的 HTML 給你。」
- 前端路由:「你要 /about 頁面?我把現在畫面的內容換成 About,順便改一下網址讓你以為換頁了。」
History API:前端路由的魔法
瀏覽器有個內建功能叫 History API,讓 JavaScript 可以:
- 改變網址列顯示的網址
- 不重新載入頁面
最小範例
// 改變網址列,但不重載頁面
window.history.pushState({}, '', '/about');
// 現在網址列顯示 /about,但頁面還是原來的
Code language: JavaScript (javascript)這在幹嘛:pushState 把 /about 加入瀏覽歷史,網址列也會顯示 /about,但不會真的去請求新頁面。
React Router 就是把這個 API 包裝起來,讓我們用更簡單的方式處理路由。
React Router v6 安裝
安裝套件
npm install react-router-dom
一句話:react-router-dom 是給網頁用的,還有一個 react-router-native 是給手機 App 用的。
30 秒範例:第一個路由
目錄結構
src/
├── App.jsx
├── pages/
│ ├── Home.jsx
│ └── About.jsx
└── main.jsx
main.jsx
import { BrowserRouter } from 'react-router-dom'; // 引入路由容器
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter> {/* 用 BrowserRouter 包住整個 App */}
<App />
</BrowserRouter>
);
Code language: JavaScript (javascript)App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
function App() {
return (
<div>
{/* 導覽列 */}
<nav>
<Link to="/">首頁</Link> {/* Link 不是 <a>,但效果一樣 */}
<Link to="/about">關於</Link>
</nav>
{/* 路由區域:根據網址顯示對應元件 */}
<Routes>
<Route path="/" element={<Home />} /> {/* / 顯示 Home */}
<Route path="/about" element={<About />} /> {/* /about 顯示 About */}
</Routes>
</div>
);
}
Code language: JavaScript (javascript)Home.jsx
function Home() {
return <h1>歡迎來到首頁</h1>;
}
export default Home;
Code language: JavaScript (javascript)About.jsx
function About() {
return <h1>關於我們</h1>;
}
export default About;
Code language: JavaScript (javascript)逐行翻譯
import { BrowserRouter } from 'react-router-dom';
// 引入 BrowserRouter,這是使用 History API 的路由容器
Code language: JavaScript (javascript)<BrowserRouter>
<App />
</BrowserRouter>
// 用 BrowserRouter 包住 App,讓裡面的元件可以使用路由功能
Code language: HTML, XML (xml)import { Routes, Route, Link } from 'react-router-dom';
// Routes:放所有路由規則的容器
// Route:單一條路由規則
// Link:點擊後切換路由的連結(不會重載頁面)
Code language: JavaScript (javascript)<Link to="/">首頁</Link>
// 像 <a href="/">,但點擊時不會重載頁面
// 改用 JavaScript 切換路由
Code language: HTML, XML (xml)<Routes>
<Route path="/" element={<Home />} />
</Routes>
// 當網址是 / 時,在這個位置顯示 <Home /> 元件
Code language: PHP (php)核心概念翻譯表
| 你會看到 | 意思 |
|---|---|
<BrowserRouter> |
路由功能的開關,包住整個 App |
<Routes> |
放路由規則的容器 |
<Route path="/" element={<Home />} /> |
網址是 / 時顯示 Home |
<Link to="/about"> |
點擊後跳到 /about(不重載頁面) |
path |
要匹配的網址路徑 |
element |
匹配成功時要顯示的元件 |
AI 最常這樣用
用法 1:基本頁面路由
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
<Route path="/contact" element={<Contact />} />
</Routes>
Code language: PHP (php)翻譯:定義三個頁面,根據網址顯示對應內容。
用法 2:有導覽列的版面
function App() {
return (
<>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<main>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</main>
<footer>Copyright 2024</footer>
</>
);
}
Code language: JavaScript (javascript)翻譯:導覽列和頁尾固定不動,只有 <Routes> 裡面的內容會隨網址改變。
用法 3:找不到頁面(404)
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} /> {/* 其他都顯示 404 */}
</Routes>
Code language: PHP (php)翻譯:path="*" 是萬用字元,匹配所有其他網址。
必看懂 vs 知道就好
必看懂(這篇會用到)
<BrowserRouter>– 路由容器<Routes>和<Route>– 定義路由規則<Link>– 不重載頁面的連結path和element– 網址對應元件
知道就好(後面的文章會教)
- 巢狀路由(
<Outlet>) - 動態路由(
/users/:id) - 程式化導航(
useNavigate) - 路由參數(
useParams)
Vibe Coder 檢查點
看到 AI 寫的路由代碼時確認:
- [ ] 有沒有用
<BrowserRouter>包住整個 App? - [ ]
<Routes>裡面是不是只有<Route>? - [ ] 連結是用
<Link>還是<a>?(應該用<Link>) - [ ] 有沒有處理 404?(
path="*") - [ ] 路由的
path和element對應正確嗎?
常見問題
Q:為什麼用 <Link> 不用 <a>?
// 錯誤:會重載整個頁面
<a href="/about">關於</a>
// 正確:只更新路由,不重載
<Link to="/about">關於</Link>
Code language: HTML, XML (xml)<a> 會觸發瀏覽器的預設行為(重載頁面),<Link> 會用 JavaScript 攔截點擊,只更新需要的部分。
Q:BrowserRouter 和 HashRouter 差在哪?
| BrowserRouter | HashRouter | |
|---|---|---|
| 網址長相 | /about |
/#/about |
| 需要伺服器設定 | 需要 | 不需要 |
| 比較常用 | 是 | 舊專案可能會看到 |
一句話:新專案用 BrowserRouter 就對了。
小結
這篇學到了:
- SPA:一個 HTML,JavaScript 切換內容
- 前端路由:改網址但不重載頁面
- React Router 三元素:
BrowserRouter– 路由容器Routes+Route– 路由規則Link– 導航連結
下一篇會教「巢狀路由」,學會怎麼讓多個頁面共用同一個版面配置。
延伸:知道就好
這些進階功能遇到再查:
- HashRouter:用
#符號的路由,不需要伺服器設定 - MemoryRouter:路由狀態存在記憶體,網址列不會變(測試用)
- StaticRouter:伺服器端渲染用的路由
- unstable_HistoryRouter:自訂 history 物件
進階測驗:React Router 快速入門
測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。
共 5 題,包含情境題與錯誤診斷題。
1. 你正在建立一個電商網站,需要有首頁、商品列表、購物車三個頁面。你希望導覽列和頁尾固定不動,只有中間內容區塊會隨網址改變。應該如何設計? 情境題
2. 小明的同事寫了以下程式碼,但點擊「關於我們」連結時,整個頁面會閃一下白畫面然後重新載入。問題出在哪裡? 錯誤診斷
<nav>
<a href=”/”>首頁</a>
<a href=”/about”>關於我們</a>
</nav>
<Routes>
<Route path=”/” element={<Home />} />
<Route path=”/about” element={<About />} />
</Routes>
3. 你要建立一個部落格網站,當使用者輸入不存在的網址(如 /xyz123)時,應該顯示「找不到頁面」的提示。應該如何實作? 情境題
4. 小華的 React 應用程式在開發時運作正常,但部署到伺服器後,直接輸入網址 https://example.com/products 會出現 404 錯誤。最可能的原因是什麼? 錯誤診斷
5. 你要在 main.jsx 中設定 React Router。以下哪個寫法是正確的? 情境題
// 選項 A
ReactDOM.createRoot(document.getElementById(‘root’)).render(
<App>
<BrowserRouter />
</App>
);
// 選項 B
ReactDOM.createRoot(document.getElementById(‘root’)).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
// 選項 C
ReactDOM.createRoot(document.getElementById(‘root’)).render(
<Routes>
<App />
</Routes>
);
// 選項 D
ReactDOM.createRoot(document.getElementById(‘root’)).render(
<Route>
<App />
</Route>
);