路由在前端开发中可以说必不可少, 这篇会对React 路由的基本使用做一个总结概括。
step1: 安装包:npm i react-router-dom (官方文档 Tutorial v6.23.1 | React Router)
step2: 创建路由实例对象并配置路由对应关系
import { createBrowserRouter } from 'react-router-dom';
import Login from '../page/Login';
import Article from '../page/Artical';
const router = createBrowserRouter([
{
path: '/login',
element: <Login />
},
{
path: '/article',
element: <Article />
}
]);
export default router;
step3: 绑定创建的router
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import reportWebVitals from './reportWebVitals';
import { RouterProvider } from 'react-router-dom';
import router from './router/index'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<RouterProvider router={router}></RouterProvider>
</React.StrictMode>
);
reportWebVitals();
以上就是React路由最最基本的配置及使用方法,下面对路由使用的不同case逐一说明。
1. 路由导航
#声明式导航#:在模板中通过<Link />组件指定要跳到哪里去
语法说明:通过给组件to属性指定要跳转到路由path, 组件会被渲染为浏览器支持的a链接。如果需要传参直接通过字符串拼接的方式拼接参数即可。
case 1: 跳转到article page 不带任何参数
<Link to="/article">Go to article page</Link>
case 2:跳转到article page 并携带search params
<Link to="/article?id=1002&&name=react">Go to article page with search params</Link>
参数获取方式:在Article组件中用useSearchParams获取查询参数
import { useSearchParams } from "react-router-dom";
function Article() {
const [params] = useSearchParams();
const id = params.get('id');
const name = params.get('name');
return <div>this is article page: search params are id-{id} name-{name}</div>;
}
export default Article;
case 3: 跳转到article page并携带路由指定参数
<Link to="/article/1001/React">Go to article page with params</Link>
相应路由配置:
{
path: '/article/:id/:name/',
element: <Article/>
}
参数获取方式:在Article组件中用useParams获取查询参数
import { useParams } from 'react-router-dom';
function Article() {
const params = useParams();
const id = params.id;
const name = params.name;
return <div>this is article page - id is {id}, name is {name}</div>
}
export default Article;
# 编程式导航#: 通过useNavigate钩子函数得到导航方法,然后通过调用方法以命令式的形式进行路由跳转, 相对声明式导航更加灵活。相应的路由配置以及参数获取方式同上面的声明式导航一致。
示例代码:
import { Link, useNavigate } from 'react-router-dom';
import './index.css'
function Login() {
const navigate = useNavigate();
return (
<div className='Login'>
<h3>this is login page</h3>
<div className='navigate'>
<p>编程式导航</p>
<button onClick={() => navigate("/article")}>Go to article page</button>
<button onClick={() => navigate("/article?id=1001&&name=React")}>Go to article with search params</button>
<button onClick={() => navigate("/article/1001/React")}>Go to article with params</button>
</div>
</div>
);
}
export default Login;
2. 路由嵌套
step1: 使用children属性配置路由嵌套关系
const router = createBrowserRouter([
{
path: '/',
element: <Container />,
children: [
{
path: '/board',
element: <Board />
},
{
path: '/about',
element: <About />
}
]
},
{
path: '/login',
element: <Login />
},
{
path: '*',
element: <NotFound />
}
]);
export default router;
step2: 使用<Outlet /> 组件配置二级路由渲染位置
import { Link, Outlet } from "react-router-dom";
import './Container.css';
function Container() {
return (
<div className="container">
<h3>this is container page</h3>
<Link className="link" to="/board">Board</Link>
<Link className="link" to="/about">About</Link>
{/* 二级路由出口 */}
<Outlet/>
</div>
);
}
export default Container;
如果想让访问一级路由的时候, 默认二级路由也可以得到渲染,只需在二级路由的位置把path改成index 并设置属性为true。 与此同时,想要跳转回baord页面,相应的跳转路径也要改为一级路由路径
<Link className="link" to="/">Board</Link>
const router = createBrowserRouter([
{
path: '/',
element: <Container />,
children: [
// 设置默认二级路由,当访问一级路由的时候,它也能得到渲染
{
index: true,
element: <Board />
},
{
path: '/about',
element: <About />
}
]
},
{
path: '/login',
element: <Login />
},
{
path: '*',
element: <NotFound />
}
]);
export default router;
3. 404路由配置
当浏览器访问的url路径在整个路由配置中都找不到相应的path,我们需要使用404 兜底组件进行渲染,提示用户访问的页面不存在。实现步骤:
step1: 准备一个NotFound组件
step2: 在路由数组的末尾,以*号作为路由path配置路由
{
path: '*',
element: <NotFound />
}
4. 两种路由模式:history模式 && hash模式
各个主流框架的路由常用的路由模式有两种,history模式和hash模式。ReactRouter分别由createBrowserRouter 和createHashRouter函数负责创建
路由模式 | url表现 | 底层原理 | 是否需要后端支持 |
history | url/login | history对象+pushState事件 | 需要 |
hash | url/#/login | 监听hashChange事件 | 不需要 |
示例代码:
const router = createHashRouter([
{
path: '/',
element: <Container />,
children: [
{
path: '/board',
element: <Board />
},
{
path: '/about',
element: <About />
}
]
},
{
path: '/login',
element: <Login />
},
{
path: '*',
element: <NotFound />
}
]);
export default router;
5. 路由懒加载
a. 什么是路由懒加载?
路由懒加载是指路由的js资源只有在被访问时才会动态获取,目的是为了优化项目首屏显示时间。
b. 如何进行配置?
step1:把路由修改为由React提供的lazy函数进行动态导入
step2:使用React内置的Suspence组件包裹路由中的element选项对应的组件
示例代码:
import { createBrowserRouter } from "react-router-dom";
import { AuthRouter} from '@/components/AuthRouter';
import App from "@/App";
import Login from "@/pages/Login";
import { Suspense, lazy } from "react";
// 实现路由懒加载
// 1. 使用lazy函数对资源进行lazy loading
const Home = lazy(() => import('@/pages/Home'));
const Artical = lazy(() => import('@/pages/Artical'));
const Publish = lazy(() => import('@/pages/Publish'));
const router = createBrowserRouter([
{
path: '/login',
element: <Login />
},
{
path: '/',
element: <App />,
//2. 用Suspens包裹路由
children: [
{
index: true,
element: <Suspense fallback="Loading..."><Home /></Suspense>
},
{
path: 'artical',
element: <Suspense fallback="loading"><Artical /></Suspense>
},
{
path: 'publish',
element: <Suspense fallback="loading"><Publish /></Suspense>
}
]
},
{
path: '*',
element: <Login />
}
]);
export default router;
6. 路由守卫
场景设置:用户login之后会获取相应token,只有在token存在的情况下才可以访问路由组件。如果没有token返回login page.
step1: 封装一个高阶组件AuthRouter
import { getToken } from '@/utils';
import { Navigate } from 'react-router-dom';
export function AuthRouter({ children }) {;
const token = getToken();
if (token) {
console.dir('children------>', children);
return <>{children}</>
} else {
console.log('Go back to login page')
return <Navigate to={'/login'} replace />
}
}
step2: 用AuthRouter包裹指定路由路径
const router = createBrowserRouter([
{
path: '/login',
element: <Login />
},
{
path: '/',
element: <AuthRouter><App /></AuthRouter>,
children: [...]
},
{
path: '*',
element: <Login />
}
]);
export default router;
总结:以上是对React路由基本使用的总结,欢迎小伙伴指导补充。^_^