Vite React router

安裝react-router

Single Page Application,中文又稱單頁式應用程式( SPA)

1
npm install --save react-router-dom@6.4.1

React Router 起手式

  • HashRouter用於 Web 瀏覽器,因為某些原因不應(或不能)將 URL 發送到服務器。
打開main.jsx檔案
  1. 引入 import { HashRouter } from "react-router-dom"
  2. HashRouter 是一個元件概念,接著只需要使用它將整個 < App /> 包起來即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import * as React from "react";
import * as ReactDOM from "react-dom";
import { HashRouter } from "react-router-dom";
import App from './App'
import './index.css'

const root=ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<HashRouter>
<App />
</HashRouter>
</React.StrictMode>
)

以上成功引入了 React Router

React Router 基本使用

使用 Route

  • path:定義路徑
  • element:定義對應的元件
1
<Route path="/todolist" element={ <ToDoList/> }>

< Route > 只能包在 < Routes > 底下使用,因此正確來講必須這樣寫才對

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react'
import { HashRouter, Route, Routes } from "react-router-dom";
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
import ToDoList from "./TodoList";

const root=ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<HashRouter>
<Routes>
<Route path="/" element={ <App /> } />
<Route path="/todolist" element={ <ToDoList /> } />
</Routes>
</HashRouter>
</React.StrictMode>
)

重新 npm run dev

打開http://localhost:3000/#/todolist

巢狀路由

路徑位置App.jsx

  • 載入import { Link } from "react-router-dom"
  • Link to="/"
App=>載入
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
import { Outlet, Link } from 'react-router-dom';

const App = () => {
return (
<>
<nav className="px-5 flex items-center h-[60px] bg-indigo-500 text-white">
<h1 className="mr-auto text-2xl">React TodoList</h1>
<ul className="flex">
<li className="mr-3">
<Link to="/" className="border p-3 hover:bg-indigo-600 duration-500">Home</Link>
</li>
<li className="mr-3">
<Link to="/todolist" className="border p-3 hover:bg-indigo-600 duration-500">ToDoList</Link>
</li>
<li className="mr-3">
<Link to="/admin" className="border p-3 hover:bg-indigo-600 duration-500">Admin</Link>
</li>
</ul>
</nav>
<h1>App</h1>
<Outlet />
</>
)
}

export default App;

路徑內容main.jsx
以下App Route 包裹 ToDoList元件
< Route path=”/“ element={} >
<Route path=”todolist” element={ } >
< /Route>
以下Admin Route 包裹 AdminProducts元件
< Route path=”/admin” element={} >
<Route path=”products” element={ } >
< /Route>

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
import React from 'react'
import ReactDOM from 'react-dom/client'
import { HashRouter, Route, Routes } from "react-router-dom";
import App from './App'
import './index.css'

import ToDoList from "./views/ToDoList";
import Admin from "./views/Admin";
import AdminProducts from './views/AdminProducts';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<HashRouter>
<Routes>
<Route path="/" element={<App />} >
<Route path="todolist" element={ <ToDoList /> } />
</Route>
<Route path="/admin" element={ <Admin /> } >
<Route path="products" element={<AdminProducts /> } />
</Route>
</Routes>
</HashRouter>
</React.StrictMode>
)

Admin =>載入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { Outlet, Link } from 'react-router-dom';

const Admin = () => {
return (
<>
<nav className="px-5 flex items-center h-[60px] bg-indigo-500 text-white">
<h1 className="mr-auto text-2xl">React TodoList</h1>
<ul className="flex">
<li className="mr-3">
<Link to="/admin" className="border p-3 hover:bg-indigo-600 duration-500">Admin</Link>
</li>
<li className="mr-3">
<Link to="/admin/products" className="border p-3 hover:bg-indigo-600 duration-500">AdminProducts</Link>
</li>
</ul>
</nav>
<h1>Admin</h1>
<Outlet />
</>
)
}

export default Admin;

NavLink 切換頁面的方式

檔案App.jsx,將 Link 通通改成 NavLink

<NavLink to=”/“ className={({ isActive }) =>
[
‘border p-3 hover:bg-indigo-600 duration-500’,
isActive ? ‘router-link-active’ : null
].join(‘ ‘)
}>Home

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
import { Outlet, Link ,NavLink} from 'react-router-dom';

const App = () =>
{

return (
<>
<nav className="px-5 flex items-center h-[60px] bg-indigo-500 text-white">
<h1 className="mr-auto text-2xl">React TodoList</h1>
<ul className="flex">
<li className="mr-3">
<NavLink to="/" className={({ isActive }) =>
[
'border p-3 hover:bg-indigo-600 duration-500',
isActive ? 'router-link-active' : null
].join(' ')
}>Home</NavLink>
</li>
<li className="mr-3">
<Link to="/todolist" className="border p-3 hover:bg-indigo-600 duration-500">ToDoList</Link>
</li>
<li className="mr-3">
<Link to="/admin" className="border p-3 hover:bg-indigo-600 duration-500">Admin</Link>
</li>
</ul>
</nav>
<h1>App</h1>
<Outlet />
</>
)
}

export default App;

檔案index.css新增以下

1
2
3
.router-link-active {
@apply bg-indigo-800;
}

React Router - Hook

//載入
import { useEffect } from “react”;
常用的 React Router Hook

  • useLocation: 載入
  • useParams: 載入
  • useNavigate: 載入
  • useRoutes: 載入

useLocation

在App.jsx內舉例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//載入
import { useEffect } from "react";
import { useLocation } from "react-router";

const App = () =>
{
const { hash, key, pathname, search, state } = useLocation();
useEffect(() => {
console.log('hash:', hash); // hash: #products
console.log('key:', key); // key: ry5x4mjc
console.log('pathname:', pathname); // pathname: /products
console.log('search:', search); // search: ?q=ray
console.log('state:', state); // state: { products: { id: '1', name: 'QQ 產品' } }
},[]);

return (
<>
<div>App</div>
</>
)
}
export default App;

useParams 動態參數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { useEffect } from "react";
import { useParams,Navigate } from 'react-router-dom';

const App = () =>
{
const { id } = useParams();
useEffect(() => {
console.log('params id:', id); // params id: 123
},[]);

return (
<>
<div>App</div>
</>
)
}
export default App;

useNavigate 重新導向

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
34
35
36
import { useEffect } from "react";
import { useNavigate } from 'react-router-dom';

const App = () =>
{
const navigate = useNavigate();
useEffect(() => {
console.log('params id:', id); // params id: 123
},[]);

return (
<>
<h1>Products</h1>
<button
className="border-1 bg-indigo-500 p-3 text-white"
onClick={ () => navigate('/products/123')}
>
點我跳轉
</button>
<button
className="border-1 bg-indigo-500 p-3 text-white"
onClick={ () => navigate(-1) }
>
前一頁
</button>
<button
className="border-1 bg-indigo-500 p-3 text-white"
onClick={ () => navigate(1) }
>
後一頁
</button>
<Outlet />
</>
)
}
export default App;

Lazy Loading:可以將我們的程式碼分割成不同的 chunk,然後在你需要或請求的時候才去載入相對應檔案

將以上改寫,新增routes資料夾index.jsx

  • 載入lazy
  • 載入useRoutes
  • 頁面載入與lazy寫法
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
34
35
36
37
38
//載入lazy
import { lazy } from 'react';
//載入useRoutes
import { useRoutes } from 'react-router-dom';
//頁面載入,路由懶加載
const App = lazy(() => import('../App'));
const ToDoList = lazy(() => import('../views/toDoList'));
const Products = lazy(() => import('../views/Products'));
const Product = lazy(() => import('../views/Product'));
const Admin = lazy(() => import('../views/admin/Admin'));

const routes = [
{
path: '/',
element: <App />,
},
{
path: '/todoList',
element: <ToDoList />,
},
{
path: "/product/:id",
element: <Product />,
},
{
path: '/admin',
element: <Admin />,
//巢狀
children: [
{
path: 'products',
element: <Products />,
}
],
}
];

export default () => useRoutes(routes);

在views /Product.jsx內
載入useParams
const { id } = useParams();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { useEffect } from "react";
import { useParams } from 'react-router-dom';
const Product = () =>{
const { id } = useParams();
useEffect(() => {
console.log('params id:', id);
},[]);
return (
<div>
<p className="text-center text-3xl mt-20">The post ID is {id}</p>
</div>
)
}

export default Product