測驗:React Router 動態路由與參數傳遞
共 5 題,點選答案後會立即顯示結果
1. 在 React Router 中,以下哪個路由定義可以匹配 /users/123 這個路徑?
2. 使用 useParams() 取得的 URL 參數值是什麼型別?
3. 如果要取得 URL 中 ?category=phone&sort=price 的參數,應該使用哪個 Hook?
4. 以下路由定義中,哪一個可以匹配 /blog/2024/03/hello-world?
匹配後,useParams() 會回傳什麼?
5. 根據文章建議,識別「特定資源」(如某個使用者、某個商品)時,應該優先使用哪種方式?
前言
在上一篇我們學會了用 Route 定義靜態路由、用 Link 切換頁面。但真實的網站不會只有 /about、/contact 這種固定路徑——你會需要 /users/1、/users/2、/products/abc123 這種「路徑中帶有變數」的頁面。
這篇文章會教你如何讀懂 React Router 的動態路由語法,以及如何在元件中取得這些參數。
學習目標
讀完本篇後,你將能夠:
- 定義動態路由參數(
:id語法) - 使用
useParamsHook 取得 URL 參數 - 使用
useSearchParams處理查詢字串 - 實作商品詳情頁、使用者頁面等動態頁面
動態路由的基本語法
認識冒號參數 :id
當你在 React Router 專案中看到這樣的程式碼:
<Route path="/users/:id" element={<UserPage />} />
Code language: JavaScript (javascript)這個 :id 就是動態參數。它的意思是:
/users/1會匹配,id的值是"1"/users/abc會匹配,id的值是"abc"/users/john-doe會匹配,id的值是"john-doe"/users不會匹配(缺少參數)
關鍵理解:冒號後面的名稱(如 id)只是變數名稱,你可以取任何有意義的名字:
// 這三個效果相同,只是參數名稱不同
<Route path="/users/:id" element={<UserPage />} />
<Route path="/users/:userId" element={<UserPage />} />
<Route path="/users/:username" element={<UserPage />} />
Code language: JavaScript (javascript)多個動態參數
路徑中可以有多個動態參數:
<Route path="/blog/:year/:month/:slug" element={<BlogPost />} />
Code language: JavaScript (javascript)這會匹配:
/blog/2024/03/hello-world/blog/2025/12/react-tips
參數值分別是:
year: "2024",month: "03",slug: "hello-world"year: "2025",month: "12",slug: "react-tips"
使用 useParams 取得參數
基本用法
當你在元件中需要讀取 URL 參數時,會看到這樣的程式碼:
import { useParams } from 'react-router-dom';
function UserPage() {
const params = useParams();
return <h1>使用者 ID: {params.id}</h1>;
}
Code language: JavaScript (javascript)讀懂這段程式碼:
useParams()是 React Router 提供的 Hook- 它回傳一個物件,包含所有動態參數
- 參數名稱對應 Route 中定義的名稱(
:id→params.id)
常見的解構寫法
實務上更常看到用解構取出參數:
function UserPage() {
const { id } = useParams();
return <h1>使用者 ID: {id}</h1>;
}
Code language: JavaScript (javascript)多個參數時:
function BlogPost() {
const { year, month, slug } = useParams();
return (
<article>
<p>發布日期: {year}/{month}</p>
<p>文章代稱: {slug}</p>
</article>
);
}
Code language: JavaScript (javascript)參數值永遠是字串
重要觀念:URL 參數永遠是字串型別。
function ProductPage() {
const { id } = useParams();
// id 是 "123"(字串),不是 123(數字)
console.log(typeof id); // "string"
// 如果要當數字用,需要轉換
const productId = Number(id);
}
Code language: JavaScript (javascript)實務範例:商品列表與詳情頁
讓我們看一個完整的範例,這是電商網站最常見的模式:
路由設定
// App.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import ProductList from './ProductList';
import ProductDetail from './ProductDetail';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/products" element={<ProductList />} />
<Route path="/products/:productId" element={<ProductDetail />} />
</Routes>
</BrowserRouter>
);
}
Code language: JavaScript (javascript)商品列表頁
// ProductList.jsx
import { Link } from 'react-router-dom';
const products = [
{ id: 1, name: 'iPhone 15' },
{ id: 2, name: 'MacBook Pro' },
{ id: 3, name: 'AirPods' },
];
function ProductList() {
return (
<ul>
{products.map(product => (
<li key={product.id}>
<Link to={`/products/${product.id}`}>
{product.name}
</Link>
</li>
))}
</ul>
);
}
Code language: JavaScript (javascript)讀懂 Link 的 to 屬性:
- 使用模板字串 `
/products/${product.id} - 當 product.id
是1,生成的路徑是/products/1
商品詳情頁
// ProductDetail.jsx
import { useParams } from 'react-router-dom';
function ProductDetail() {
const { productId } = useParams();
// 實際專案中,這裡會用 productId 去 API 取得商品資料
// 例如: useEffect(() => { fetch(`/api/products/${productId}`) }, [productId])
return (
<div>
<h1>商品詳情</h1>
<p>商品 ID: {productId}</p>
</div>
);
}
Code language: JavaScript (javascript)查詢字串(Query String)
什麼是查詢字串?
URL 中 ? 後面的部分就是查詢字串:
/products?category=phone&sort=price
^^^^^^^^^^^^^^^^^^^^^^^^^^ 查詢字串
查詢字串常用於:
- 篩選條件:?category=phone
- 排序方式:?sort=price&order=desc
- 分頁:?page=2&limit=10
- 搜尋關鍵字:?q=react
使用 useSearchParams
import { useSearchParams } from 'react-router-dom';
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
// 讀取參數
const category = searchParams.get('category');
const sort = searchParams.get('sort');
return (
<div>
<p>分類: {category || '全部'}</p>
<p>排序: {sort || '預設'}</p>
</div>
);
}
Code language: JavaScript (javascript)讀懂這段程式碼:
- useSearchParams()
回傳陣列[searchParams, setSearchParams] - searchParams.get(‘category’)
取得category參數的值 - 如果參數不存在,get()
回傳null
修改查詢字串
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
const handleCategoryChange = (newCategory) => {
// 設定新的查詢字串,URL 會變成 ?category=phone
setSearchParams({ category: newCategory });
};
const handleAddSort = () => {
// 保留現有參數,新增 sort
searchParams.set('sort', 'price');
setSearchParams(searchParams);
};
return (
<div>
<button onClick={() => handleCategoryChange('phone')}>
只看手機
</button>
<button onClick={handleAddSort}>
依價格排序
</button>
</div>
);
}
Code language: JavaScript (javascript)動態路由 vs 查詢字串:何時用哪個?
| 情境 | 建議使用 | 範例 |
|---|---|---|
| 識別特定資源 | 動態路由 | /users/123, /products/abc |
| 篩選/排序/分頁 | 查詢字串 | ?sort=price&page=2 |
| 需要被搜尋引擎索引 | 動態路由 | /blog/2024/my-post |
| 使用者可選的條件 | 查詢字串 | ?theme=dark |
簡單記法:
- 「哪一個」→ 動態路由(/products/:id
) - 「怎麼顯示」→ 查詢字串(?sort=price
)
常見程式碼模式
模式一:詳情頁載入資料
function UserProfile() {
const { userId } = useParams();
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]); // userId 變化時重新載入
if (!user) return <p>載入中...</p>;
return <h1>{user.name}</h1>;
}
Code language: JavaScript (javascript)模式二:列表頁篩選
function ProductList() {
const [searchParams] = useSearchParams();
const category = searchParams.get('category');
const [products, setProducts] = useState([]);
useEffect(() => {
const url = category
? `/api/products?category=${category}`
: '/api/products';
fetch(url)
.then(res => res.json())
.then(data => setProducts(data));
}, [category]);
return (
<ul>
{products.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
);
}
Code language: JavaScript (javascript)重點整理
| 概念 | 語法 | 用途 |
|---|---|---|
| 動態路由參數 | path=”/users/:id” |
定義 URL 中的變數位置 |
| useParams | const { id } = useParams() |
在元件中取得路徑參數 |
| 查詢字串 | ?key=value |
URL 問號後的參數 |
| useSearchParams | const [params] = useSearchParams()` | 讀取/修改查詢字串 |
下一步
學會動態路由後,下一篇我們將學習「巢狀路由與 Outlet」,這是建立複雜頁面結構(如側邊欄佈局、儀表板)的關鍵技巧。
進階測驗:React Router 動態路由與參數傳遞
共 5 題,包含情境題與錯誤診斷題。
1. 你正在開發電商網站的商品詳情頁 情境題
需求是當使用者點擊商品列表中的商品時,跳轉到 /products/商品ID 頁面並顯示該商品資訊。你需要在詳情頁元件中取得商品 ID 後呼叫 API。以下哪種寫法最正確?
2. 你需要實作商品列表的篩選功能 情境題
使用者可以選擇分類和排序方式,URL 會變成 /products?category=phone&sort=price。當使用者點擊「手機」分類按鈕時,你想要更新 URL 的 category 參數但保留其他參數。以下哪種做法最適合?
3. 設計部落格文章的 URL 結構 情境題
你需要設計部落格的 URL,希望 URL 能包含年份、月份和文章代稱,方便 SEO 和分享。例如:/blog/2024/03/react-router-intro。以下哪個路由定義最合適?
4. 除錯:商品 ID 比對失敗 錯誤診斷
小明寫了一個商品詳情頁,但發現商品資料一直找不到。以下是他的程式碼:
假設 products 資料正確,p.id 是數字型別,最可能的問題是什麼?
5. 除錯:useEffect 無限迴圈 錯誤診斷
小美寫了一個會根據篩選條件重新載入商品的頁面,但瀏覽器卻陷入無限迴圈,一直發送 API 請求:
造成無限迴圈的最可能原因是什麼?