一拄氯、安裝
npm install react-router-dom@6 -S
二、使用
我們使用vite初始化react項(xiàng)目:
yarn create vite react-router-v6-demo --template react
更多關(guān)于vite的使用码耐,參考vite官網(wǎng)
1. 基本的路由配置
// main.jsx 入口文件
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// App.jsx
import React from 'react';
import './App.css';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import BasicLayout from './layout/BasicLayout';
import Home from './pages/Home';
import ArticleList from './pages/ArticleList';
import Detail from './pages/Detail';
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<BasicLayout />}>
<Route index element={<Home />} />
<Route path='articleList' element={<ArticleList />} />
<Route path='articleList/:id' element={<Detail />} />
<Route path='*' element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;
最外層的Route里面包含了四條路由(嵌套路由倾剿,后面會(huì)詳細(xì)說(shuō)明),其中:
index
表示是索引路由张肾。當(dāng)?shù)刂窞?/'的時(shí)候,默認(rèn)打開(kāi) Home 頁(yè)面锚扎。
path='articleList/:id'
是路由傳參吞瞪,比較適用于列表詳情的場(chǎng)景,通過(guò)不同的id展示不同的文章驾孔。
path='\*'
表示可以匹配任何路由芍秆,當(dāng)找不到路由時(shí)候,會(huì)默認(rèn)跳到 NotFound 頁(yè)面翠勉。
2. 嵌套路由
在Route中包含子路由即可妖啥,如下:
// ...
<Route path='/' element={<BasicLayout />}>
<Route index element={<Home />} />
<Route path='articleList' element={<ArticleList />} />
<Route path='articleList/:id' element={<Detail />} />
<Route path='*' element={<NotFound />} />
</Route>
// ..
// BasicLayout/index.jsx
import React from 'react';
import styles from './index.module.scss';
import { Link, Outlet } from 'react-router-dom';
const BasicLayout = () => {
return (
<div className={styles.basicLayout}>
<div className={styles.nav}>
<Link to='/'>Home</Link> | <Link to='articleList'>ArticleList</Link>
</div>
{/* Outlet相當(dāng)于是子路由的占位符 */}
<Outlet />
</div>
);
};
export default BasicLayout;
需要注意的是 BasicLayout 里面的 <Outlet />
,相當(dāng)于是子路由的占位符对碌,不可缺少荆虱。
3.路由傳參
有兩種形式傳參。第一種直接使用路由傳參朽们,第二種通過(guò)query的形式傳參(也就是url后加?xx=xx)的形式怀读。
直接路由傳參的話,需要配置路由骑脱,如下:
<Route path='articleList/:id' element={<Detail />} />
跳轉(zhuǎn)前的頁(yè)面參數(shù)傳值:
// ArticleList/index.jsx
import React from 'react';
import styles from './index.module.scss';
import { useNavigate } from 'react-router-dom';
const ArticleList = () => {
const navigate = useNavigate();
return (
<div className={styles.articleList}>
這里是articleList頁(yè)面
<ul>
<li onClick={() => navigate('/articleList/1?author=jack&age=18')}>文章1</li>
<li onClick={() => navigate('/articleList/2')}>文章2</li>
<li onClick={() => navigate('/articleList/3')}>文章3</li>
</ul>
</div>
);
};
最后菜枷,在詳情頁(yè)面接收我們的傳參:
// Detail/index.jsx
import React from 'react';
import styles from './index.module.scss';
import { useParams } from 'react-router-dom';
const Detail = () => {
const params = useParams();
const [searchParams] = useSearchParams();
console.log('searchParams', searchParams.getAll('author')[0]); // jack
return <div className={styles.detail}>{`這里是文章${params.id}`}</div>;
};
export default Detail;
我們通過(guò)useNavigate
來(lái)進(jìn)行跳轉(zhuǎn)頁(yè)面,useParams
或者 useSearchParams
來(lái)接收不同形式的傳參惜姐。
4. 路由監(jiān)聽(tīng)
import React, { useEffect } from 'react';
import styles from './index.module.scss';
import { useLocation } from 'react-router-dom';
const NotFound = () => {
const location = useLocation();
useEffect(() => {
console.log(location.pathname, "enter")
return () => {
console.log(location.pathname, "leave")
}
}, [location.pathname])
return <div className={styles.notFound}>404</div>;
};
export default NotFound;
我們可以使用 useLocation
來(lái)獲取我們的當(dāng)前路由的信息犁跪,然后通過(guò) useEffect
來(lái)監(jiān)聽(tīng)椿息,從而實(shí)現(xiàn)路由監(jiān)聽(tīng)歹袁。
5.路由對(duì)象
日常開(kāi)發(fā)中坷衍,一般會(huì)把路由分開(kāi),單獨(dú)寫(xiě)一個(gè)配置文件条舔。
react-router-dom v6 提供了路由對(duì)象的支持枫耳,我們可以把路由寫(xiě)成一個(gè)對(duì)象,然后通過(guò) useRoutes 來(lái)解析孟抗。
// config/router.config.jsx
import React from 'react';
import BasicLayout from '../src/layout/BasicLayout';
import Home from '../src/pages/Home';
import ArticleList from '../src/pages/ArticleList';
import Detail from '../src/pages/Detail';
import NotFound from '../src/pages/NotFound';
const routes = [
{
path: '/',
element: <BasicLayout />,
children: [
{
index: true,
element: <Home />
},
{
path: 'articleList',
element: <ArticleList />
},
{
path: 'articleList/:id',
element: <Detail />
},
{
path: '*',
element: <NotFound />
}
]
}
];
export default routes;
// App.jsx
import React from 'react';
import './App.css';
import { useRoutes } from 'react-router-dom';
import routes from '../config/router.config'
const App = () => <>{useRoutes(routes)}</>
export default App;
// main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
其實(shí)也可以自己手寫(xiě)一個(gè) getRoutes 方法來(lái)從配置文件中解析出路由迁杨。
App.jsx
import React from 'react';
import './App.css';
import { useRoutes, Routes, Route } from 'react-router-dom';
import routes from '../config/router.config';
const getRoutes = (routes) => {
const routesElement = routes.map((item, index) => {
return (
<Route index={item.index} path={item.path} element={item.element} key={`${item.path}${index}`}>
{item.children?.length ? getRoutes(item.children) : null}
</Route>
);
});
return routesElement;
};
// const App = () => <>{useRoutes(routes)}</>
const App = () => <Routes>{getRoutes(routes)}</Routes>
export default App;
6. 路由懶加載
通過(guò)動(dòng)態(tài) import 導(dǎo)入,能夠打包成單獨(dú)的 chunk凄硼。
再加上 react 提供的懶加載api lazy
與 Suspense
即可實(shí)現(xiàn)路由懶加載铅协。
// config/router.config.jsx
import React, { Suspense, lazy } from 'react';
import BasicLayout from '../src/layout/BasicLayout';
const lazyLoad = (src) => <Suspense fallback={<>...</>}>{React.createElement(lazy(src))}</Suspense>;
const routes = [
{
path: '/',
element: <BasicLayout />, // BasicLayout是基本布局,不必使用懶加載
children: [
{
index: true,
element: lazyLoad(() => import('../src/pages/Home'))
},
{
path: 'articleList',
element: lazyLoad(() => import('../src/pages/ArticleList'))
},
{
path: 'articleList/:id',
element: lazyLoad(() => import('../src/pages/Detail'))
},
{
path: '*',
element: lazyLoad(() => import('../src/pages/NotFound'))
}
]
}
];
export default routes;```
// App.jsx
import React from 'react';
import './App.css';
import { useRoutes } from 'react-router-dom';
import routes from '../config/router.config';
const App = () => <>{useRoutes(routes)}</>;
export default App;
這樣就實(shí)現(xiàn)了路由懶加載摊沉。每次打開(kāi)新的路由時(shí)狐史,就會(huì)請(qǐng)求該路由對(duì)應(yīng)組件的資源。
具體效果圖:
![](https://upload-images.jianshu.io/upload_images/1745991-1a63d5bed0958229.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
完整源碼已上傳github:
https://github.com/RhysZhao/react-router-v6-demo
**參考資料:**
[React Router v6官方文檔](https://reactrouter.com/docs/en/v6/getting-started/overview)