EP05 | React 18 全家桶複習 - React-Router
React Router v6
標籤
路由定義: 根據不同的 url 地址顯示不同內容或頁面。
基礎使用:
下載: 在專案中下載 react-router-dom 工具
1
npm i react-router-dom
補充: react-router-dom 是包含了 react-router (路由核心庫),並添加一洩專用於 DOM 的組件。
實現最小化 Demo,實現 Home 與 About 頁面的切換
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34import { BrowerRouter, Link, Routers, Router } from 'react-router-dom'
function Home() {
return (
<div>
我是 Home
</div>
)
}
function About() {
return (
<div>
我是 About
</div>
)
}
export default function App() {
return (
{/*聲明當前要用一個非 hash 模式的路由*/}
<BrowerRouter>
{/*指定跳轉的組件, to 用來配置路由地址*/}
<Link to="/">首頁</Link>
<Link to="/about">關於</Link>
{/*路由出口,路由對應的組件在這裡渲染*/}
<Routes>
{/*指定路徑和組件的對應關係, path 代表路徑, element 代表組件 path 跟 element 成對出現*/}
<Route path="/" element={<Home/>} />
<Route path="/about" element={<About/>} />
<Routes>
</BrowerRouter>
)
}
BrowerRouter、 Link、 Routers、 Router 是使用 ReactRouter 基礎的使用,配置大致如上。
比較 BrowerRouter 與 HashRouter
- BrowerRouter 呈現的 url
localhost:5500/home
- HashRouter 呈現的 url
localhost:5500/#/home
NavLink 與 Link
Link
- 基本寫法:
<Link to="/home">首頁</Link>
。 - 類似
<a href="../home">首頁</a>
- 連結被點選時,不會主動產生
active
(class 屬性值)。
- 基本寫法:
NavLink
- 基本寫法:
<NavLink to="/home">首頁</NavLink>
。 - 當被點擊時,預設會產生
active
(class 屬性值)。 - 類似
<a href="../home" class="active">首頁</a>
。 - 透過將函數傳給 className 或 style 就可自訂義
active
的名稱。1
2
3
4
5let activeClassName = 'underline';
// isActive 是連結渲染時,該函數就會被調用,傳給他的一個 object去判斷目前是否被點選
<NavLink to='/home' className={({ isActive }) => (isActive ? activeClassName : undefined)}>
首頁
</NavLink>;
- 基本寫法:
useRoutes 路由表、Outlet 嵌套路由標籤
在寫路由與組件的對應關係時,會發現其實配置是相似的,都是由 path 跟 element 組成。
1 | {/*指定路徑和組件的對應關係, path 代表路徑, element 代表組件 path 跟 element 成對出現*/} |
為了讓頁面更簡潔,更能夠實現狀態管理的方便性,將上面的路由變成一個路由表 ⬇️⬇️⬇️
1 | // routes.js |
二級路由的頁面需要使用到 Outlet 標籤跟 React 說明,二級路由所設定的畫面要放在哪位置 ⬇️
1 | // Home.js |
路由傳參
在很多時候,是需要透過動態傳參給路由,來呈現不同產品頁面的。
1 | export default [ |
useParams
寫法(路由表):
path: "message/:id"
:id 就是路由接收組件傳遞的參數的值。可以多重結合
path: "message/:id/:name"
抽出 home 中的 message 做範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14{
path: '/home',
element: <Home />,
children: [
{
path: 'message/:id/:name',
element: <Message />,
},
{
path: 'news',
element: <News />,
},
],
}傳參組件傳遞參數寫法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// Home.js
import { Outlet, Link } from 'react-router-dom';
function Home() {
return (
<div>
我是 Home 頁<br />
<Link to='message/1234/Celeste'>訊息</Link>
<br />
<Link to='news'>新聞</Link>
<hr />
我是二級路由呈現位置
<Outlet />
</div>
);
}url 呈現
localhost:5500/home/message/1234/Celeste
此時的 1234 就是組件傳遞的 id 的參數值,而 Celeste 就是 name 的參數值。組件透過 useParams 接收參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14import { useParams } from 'react-router-dom';
export default function Message() {
const params = useParams();
console.log(params); // {id: 1234, name: 'Celeste'}
// 解構
const [id, name] = useParams();
return (
<div>
id: {id}
<br />
name: {name}
</div>
);
}
useSearchParams
寫法(路由表):
path: "news"
?id 就是路由接收組件傳遞的 search 參數的值。
search 參數不用佔位。抽出 home 中的 news 做範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15{
path: '/home',
element: <Home />,
children: [
{
path: 'message/:id/:name',
element: <Message />,
},
{
// search 參數不需要再路由表中呈現
path: 'news',
element: <News />,
},
],
}傳參組件傳遞參數寫法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// Home.js
import { Outlet, Link } from 'react-router-dom';
function Home() {
return (
<div>
我是 Home 頁<br />
<Link to='message/1234/Celeste'>訊息</Link>
<br />
<Link to='news?id=1234&name=Celeste'>新聞</Link>
<hr />
我是二級路由呈現位置
<Outlet />
</div>
);
}url 呈現
localhost:5500/home/news?id=1234&name=Celeste
此時的 1234 就是組件傳遞的 id 的 search 參數值,而 Celeste 就是 name 的參數值。組件透過 useSearchParams 接收參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import { useSearchParams } from 'react-router-dom';
export default function News() {
const searchParams = useSearchParams();
console.log(searchParams); // 是一個陣列 [URLSearchParams, f]
// useSearchParams 傳的值跟 useState 很像,第一個就是 search 參數,第二個是更新 search 的方法
const [search, setSearch] = useSearchParams();
// 此時的 search 還不能直接被查看,需透過 get(查看的參數名) 來查看
console.log(search.get('id'));
console.log(search.get('name'));
return (
<div>
id: {search.get('id')}
<br />
name: {search.get('name')}
<button onClick={() => setSearch('id=9876&name=Smith')}>改變 search 參數</button>
</div>
);
}
除了上面 2 個接收參數的方法外,還可以使用 useLocation
或 useMatches
來取得頁面更詳細的訊息。
如果透過 state (此 state 非彼 state)來傳路由參數的話,就需要用 useLocation
來接收 state 參數:
1 | <Link |
透過 useLocation
來接收
1 | // News.js |
其他 Hooks
useNavigate
實現編程式導航。
寫法:
useNavigate()(路徑, options: { replace, state})
範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import { useNavigate } from 'react-router-dom';
export default function App(){
const navigate = useNavigate();
return (
我是 App <br/>
<button onClick={() => {
navigate("/about", {
// replace 在歷史紀錄上是否取代跳轉前的頁面
replace: false, // 預設
// 傳遞 state 參數給跳轉的頁面
state: { id: 1234, name: "Celeste" },
})
}}>點選我跳轉到 About</button>
)
}跳轉上一頁或下一頁
useNavigate()(-1)
跳轉上一頁useNavigate()(1)
跳轉下一頁
useNavigationType
查看進入該路徑時,是透過 PUSH、 REPLACE、POP(刷新頁面或直接進入) 哪一種。
1
2
3
4
5
6// News.js
import { useLocation, useNavigationType } from 'react-router-dom';
export default function News() {
console.log(useNavigationType()); // PUSH、 REPLACE、POP
return <div>我是 News</div>;
}useOutlet
查看目前組件中的嵌套路由組件內容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// Home.js
import { Outlet, Link, useOutlet } from 'react-router-dom';
function Home() {
console.log(useOutlet()); // 當嵌套路由組件掛載時,就可以查看相關訊息
return (
<div>
我是 Home 頁<br />
<Link to='message'>訊息</Link>
<br />
<Link to='news'>新聞</Link>
<hr />
我是二級路由呈現位置
<Outlet />
</div>
);
}