一、安装
npm install react-router-dom@6 -S
二、使用
我们使用vite初始化react项目:
yarn create vite react-router-v6-demo --template react
更多关于vite的使用,参考vite官网
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里面包含了四条路由(嵌套路由,后面会详细说明),其中:
index
表示是索引路由。当地址为'/'的时候,默认打开 Home 页面。
path='articleList/:id'
是路由传参,比较适用于列表详情的场景,通过不同的id展示不同的文章。
path='\*'
表示可以匹配任何路由,当找不到路由时候,会默认跳到 NotFound 页面。
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相当于是子路由的占位符 */}
<Outlet />
</div>
);
};
export default BasicLayout;
需要注意的是 BasicLayout 里面的 <Outlet />
,相当于是子路由的占位符,不可缺少。
3.路由传参
有两种形式传参。第一种直接使用路由传参,第二种通过query的形式传参(也就是url后加?xx=xx)的形式。
直接路由传参的话,需要配置路由,如下:
<Route path='articleList/:id' element={<Detail />} />
跳转前的页面参数传值:
// 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页面
<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>
);
};
最后,在详情页面接收我们的传参:
// 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;
我们通过useNavigate
来进行跳转页面,useParams
或者 useSearchParams
来接收不同形式的传参。
4. 路由监听
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
来获取我们的当前路由的信息,然后通过 useEffect
来监听,从而实现路由监听。
5.路由对象
日常开发中,一般会把路由分开,单独写一个配置文件。
react-router-dom v6 提供了路由对象的支持,我们可以把路由写成一个对象,然后通过 useRoutes 来解析。
// 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>
);
其实也可以自己手写一个 getRoutes 方法来从配置文件中解析出路由。
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. 路由懒加载
通过动态 import 导入,能够打包成单独的 chunk。
再加上 react 提供的懒加载api lazy
与 Suspense
即可实现路由懒加载。
// 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;
这样就实现了路由懒加载。每次打开新的路由时,就会请求该路由对应组件的资源。
具体效果图:
![](https://img.haomeiwen.com/i1745991/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)
网友评论