创建路由开发环境

1
2
# 安装最新的ReactRouter包
npm i react-router-dom

简单的路由实例

index.js 中,实现一个简单的路由实例

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
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store'
import { Provider } from 'react-redux';
// 导入router组件
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
// 创建router实例对象并配置路由对应关系
const router = createBrowserRouter([
  {
    path: '/',
    element: <App></App>
  },
  {
    path: '/login',
    element: <div>我是登录页</div>
  },
  {
    path: '/article',
    element: <div>我是文章页</div>
  }
])

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
  {/* 在组件中使用RouterProvider实现路由 */}
    <RouterProvider router={router}></RouterProvider>
  </Provider>
);

抽象路由模块

page/模块

image.png

1
2
3
4
5
const Login = () => {
  return <div>我是登录页</div>
}

export default Login

router模块

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import App from '../App';
import Login from "../page/login";
import Article from "../page/article";
import { createBrowserRouter } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: '/',
    element: <App></App>
  },
  {
    path: '/login',
    element: <Login></Login>
  },
  {
    path: '/article',
    element: <Article></Article>
  }
])

export default router

应用入口文件渲染 RouterProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react';
import ReactDOM from 'react-dom/client';
import store from './store'
import { Provider } from 'react-redux';
// 导入router
import { RouterProvider } from 'react-router-dom';
import router from './router';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
  // 注入router
    <RouterProvider router={router}></RouterProvider>
  </Provider>
);

路由导航

声明式导航

声明式导航是指通过在模版中通过 <Link/>  组件描述出要跳转到哪里去

1
2
3
4
5
6
7
8
9
import { Link } from "react-router-dom"

const Login = () => {
  return (
    <div>我是登录页<Link to="/">主页</Link></div>
  )
}

export default Login

通过给组件的to属性指定要跳转到路由path,组件会被渲染为浏览器支持的a链接,如果需要传参直接通过字符串拼接的方式拼接参数即可

编程式导航

编程式导航是指通过 useNavigate 钩子得到导航方法,然后通过调用方法以命令式的形式进行路由跳转

1
2
3
4
5
6
7
8
9
10
11
12
import { useNavigate } from "react-router-dom"

const Login = () => {
  const navigate = useNavigate()
  return (
    <div>我是登录页
      <button onClick={() => navigate('/article')}>文章</button>
    </div>
  )
}

export default Login

通过调用 navigate方法 传入地址 path 实现跳转

导航传参

searchParams 传参

1
2
// 原路由处传递参数
<button onClick={() => navigate('/article?id=666&name=Alien')}>文章(传参)</button>
1
2
3
// 目标路由处接收参数
const [params] = useSearchParams()
<div>{params.get('id')}{params.get('name')}</div>

params 传参

1
2
3
4
5
// 在router配置文件
{
path: '/login/:id',
element: <Login></Login>
},
1
2
// 原路由处传递参数
<button onClick={() => navigate('/login/1001')}>登录(传参)</button>
1
2
3
// 目标路由处接收参数
const params = useParams()
<div>{params.id}</div>

嵌套路由配置

实现步骤

  1. 使用 children属性配置路由嵌套关系
  2. 使用 <Outlet/> 组件配置二级路由渲染位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
path: '/',
element: <Layout />,
children: [
{
path: 'about',
element: <About />,
},
{
path: 'board',
element: <Board />,
}
]
}
1
2
3
4
5
6
7
8
9
10
const Layout = () => {
return (
<div>
<Link to="/about">关于</Link>
<Link to="/board">面板</Link>
{/* 二级路由出口 */}
<Outlet />
</div>
)
}

默认二级路由

当访问的是一级路由时,默认的二级路由组件可以得到渲染,只需要在二级路由的位置去掉path,设置index属性为true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
path: '/',
element: <Layout />,
children: [
{
index: true,
element: <About />,
},
{
path: 'board',
element: <Board />,
}
]
}

404路由配置

场景:当浏览器输入url的路径在整个路由配置中都找不到对应的 path,为了用户体验,可以使用 404 兜底组件进行渲染

实现步骤

  1. 准备一个 NotFound组件
  2. 在路由表数组的末尾,以*号作为路由path配置路由
1
2
3
4
5
6
// 准备一个 NotFound组件
const NotFound = () => {
  return <div>404找不到目标</div>
}

export default NotFound
1
2
3
4
5
// 在路由表配置*号地址
{
path: '*',
element: <NotFound></NotFound>
}

两种路由模式

各个主流框架的路由常用的路由模式有俩种,history模式hash模式,ReactRouter 分别由 createBrowerRoutercreateHashRouter 函数负责创建

路由模式 url表现 底层原理 是否需要后端支持
history url/login history对象 + pushState事件 需要
hash url/#/login 监听hashChange事件 不需要