一、路由快速上手

1、什么是前端路由

一个路径 path 对应一个组件 component 当我们在浏览器中访问一个 path 的时候,path 对应的组件会在页面中进行渲染

image

2、创建路由开发环境

# 使用CRA创建项目
npx create-react-app react-router-pro
cd react-router-pro
# 安装最新的ReactRouter包
npm i react-router-dom

# 启动项目
npm run start

3、快速开始

浏览器中输入/login时,显示登录页面。输入/article的时候,显示文章页面。

image

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import { createBrowserRouter,RouterProvider } from 'react-router-dom';
// 创建router实例对象,并且配置路由对应关系
const router = createBrowserRouter([
  {
    path: '/login',
    element: <div>我是登录页面</div>
  },
  {
    path: '/article',
    element: <div>我是文章页面</div>
  }
])
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouterProvider router={router}/>
    {/* <App /> */}
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

效果:

image

上面的代码有两个问题:

(1)、通常路由对应的组件非常复杂,不是一个简单的元素div,通常是一个组件

(2)、直接把路由放到入口的index.js文件中是不合理的,通常时放到router模块

抽象路由模块

image

(1)、新增Login组件和Article组件,这个组件称为路由级别的组件,专门和路由进行绑定

在src目录下新建page文件夹,在page目录下新建Login目录和Article目录(通常除了js文件,还有样式文件),各自新增index.js文件

Article/index.js文件的内容如下:

const Article =() => 
    {
    return <div>我是文章页</div>
}
export default Article

Login/index.js文件的内容如下:

const Login =() => 
    {
    return <div>我是登录页</div>
}
export default Login

目录结构如下:

image

(2)、创建一个router模块,把第一步创建的组件引进来,配置path和component,

在src目录下创建router目录,router目录下创建index.js文件,内容如下:

import Login from '../page/Login'
import Article from '../page/Article'

import { createBrowserRouter } from 'react-router-dom'

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

export default router

(3)、通过RouterProvider注入router实例

src/index.js文件内容如下:

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'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouterProvider router={router}/>
    {/* <App /> */}
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

二、路由导航

1、什么是路由导航

路由系统中的多个路由之间需要进行路由跳转,并且在跳转的同时有可能需要传递参数进行通信。比如从文章列表页跳转到文章详情页就是路由跳转,而且跳转的时候需要携带id参数

image

我们已经完成了登录页和文章页两个路由,假设在登录页中有一个Button按钮,点击Button按钮的时候跳转到文章页,

修改Login/index.js文件

import {Link} from 'react-router-dom'
const Login =() => {
    return (
        <div>
            我是登录页
            <Link to="/article">跳转到文章页</Link>
        </div>
    )
}
export default Login

效果如下:

imageimage

2、声明式导航

声明式导航是指通过在模版中通过 <Link/> 组件描述出要跳转到哪里去,比如后台管理系统的左侧菜单通常使用这种方式进行

<Link to="/article">文章</Link>

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

3、编程式导航

编程式导航是指通过 useNavigate 钩子得到导航方法,然后通过调用方法以命令式的形式进行路由跳转,比如想在登录请求完毕之后跳转就可以选择这种方式,更加灵活

import { useNavigate } from "react-router-dom"
const Login =() => {
    const navigate = useNavigate()
    return (
        <div>
            我是登录页
            <button onClick={()=>{navigate('/article')}}>跳转至文章页</button>
        </div>
    )
}
export default Login

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

导航传参

image

1、searchParams传参

接收参数的时候用到固定的钩子函数useSearchParams

Login/index.js

import { useNavigate } from "react-router-dom"
const Login =() => {
    const navigate = useNavigate()
    return (
        <div>
            我是登录页
            <button onClick={()=>{navigate('/article?id=1001&name=jack')}}>跳转至文章页</button>
        </div>
    )
}
export default Login

Article/index.js

import {useSearchParams} from "react-router-dom"
const Article =() => {
    const [params] = useSearchParams()
    const id = params.get('id')
    const name = params.get('name')
    return <div>我是文章页-{id}-{name}</div>
}
export default Article

效果:

image

2、Params传参

Login/index.js

import { useNavigate } from "react-router-dom"
const Login =() => {
    const navigate = useNavigate()
    return (
        <div>
            我是登录页
            <button onClick={()=>{navigate('/article/1001')}}>跳转至文章页</button>
        </div>
    )
}
export default Login

修改router/index.js

import Login from '../page/Login'
import Article from '../page/Article'

import { createBrowserRouter } from 'react-router-dom'

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

export default router

Article/index.js

import {useParams} from "react-router-dom"
const Article =() => {
    const params = useParams()
    let id = params.id
    return <div>我是文章页-{id}</div>
}
export default Article

效果如下:

image

如果还想传递一个name参数,则相应修改如下:

Login/index.js

<button onClick={()=>{navigate('/article/1001/jack')}}>跳转至文章页</button>

router/index.js

{
        path: '/article/:id/:name',
        element: <Article/>
    }

Article/index.js

import {useParams} from "react-router-dom"
const Article =() => {
    const params = useParams()
    let id = params.id
    let name = params.name
    return <div>我是文章页-{id}-{name}</div>
}
export default Article

 

三、嵌套路由配置

1、什么是嵌套路由

在一级路由中又内嵌了其他路由,这种关系就叫做嵌套路由,嵌套至一级路由内的路由又称作二级路由,例如:

image

上图是一个后台管理系统,Layout component为一级路由,左侧是一个菜单,右侧是一个二级路由出口。当点击看板的时候,二级路由出口会显示看板对应的二级路由组件内容,当点击关于的时候,又会切换到关于组件的内容

2、嵌套路由配置

实现步骤

  1. 使用 children属性配置路由嵌套关系

  2. 使用 <Outlet/> 组件配置二级路由渲染位置

image

page目录下新建Layout目录,然后Layout目录下再新建index.js,内容如下:

const Layout = ()=>{
    return(
        <div>
            我是一级路由Layout组件
        </div>
    )
}
export default Layout

page目录下新建About目录,然后About目录下再新建index.js,内容如下:

const About = ()=>{
    return (
        <div>
            我是关于页
        </div>
    )
}
export default About

page目录下新建Board目录,然后Board目录下再新建index.js,内容如下:

const Board = ()=>{
    return (
        <div>
            我是面板页
        </div>
    )
}
export default Board

在router/index.js中配置嵌套路由

import Login from '../page/Login'
import Article from '../page/Article'
import Layout from '../page/Layout'
import Board from '../page/Board'
import About from '../page/About'

import { createBrowserRouter } from 'react-router-dom'
import Board from '../page/Board'

const router = createBrowserRouter([
    {
        path: '/',
        element: <Layout/>,
        children: [
            {
                path: 'board',
                element: <Board/>
            },
            {
                path: 'about',
                element: <About/>
            }
        ]
    },
    {
        path: '/login',
        element: <Login/>
    },
    {
        path: '/article/:id/:name',
        element: <Article/>
    }
])

export default router

在Layout/index.js中使用‘<Outlet/>’组件配置二级路由渲染位置

import {Link,Outlet} from 'react-router-dom'
const Layout = ()=>{
    return(
        <div>
            我是一级路由Layout组件
            <Link to="/board">看板</Link>
            <Link to="/about">关于</Link>
            {/* 配置二级路由的出口 */}
            <Outlet/>
        </div>
    )
}
export default Layout

效果:

image

3、默认二级路由

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

image

import Login from '../page/Login'
import Article from '../page/Article'
import Layout from '../page/Layout'
import Board from '../page/Board'
import About from '../page/About'

import { createBrowserRouter } from 'react-router-dom'

const router = createBrowserRouter([
    {
        path: '/',
        element: <Layout/>,
        children: [
            {
                // path: 'board',
                index: true,
                element: <Board/>
            },
            {
                path: 'about',
                element: <About/>
            }
        ]
    },
    {
        path: '/login',
        element: <Login/>
    },
    {
        path: '/article/:id/:name',
        element: <Article/>
    }
])

export default router

效果如下:

image

由于router/index.js中去掉了/board,此时还需要修改Layout/index.js,将看板的路由改为/

import {Link,Outlet} from 'react-router-dom'
const Layout = ()=>{
    return(
        <div>
            我是一级路由Layout组件
            <Link to="/">看板</Link>
            <Link to="/about">关于</Link>
            {/* 配置二级路由的出口 */}
            <Outlet/>
        </div>
    )
}
export default Layout

 

4、404路由配置

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

实现步骤:

  1. 准备一个NotFound组件

  2. 在路由表数组的末尾,以*号作为路由path配置路由,*号表示通配符,表示如果上面的地址都无法匹配,则有它来匹配

image

在page目录下创建notFound目录,该目录下新建index.js文件,内容如下:

const NotFound = ()=>{
    return (
        <div>
            this is NotFound
        </div>
    )
}
export default NotFound

修改router/index.js

import Login from '../page/Login'
import Article from '../page/Article'
import Layout from '../page/Layout'
import Board from '../page/Board'
import About from '../page/About'
import NotFound from '../page/NotFound'
import { createBrowserRouter } from 'react-router-dom'

const router = createBrowserRouter([
    {
        path: '/',
        element: <Layout/>,
        children: [
            {
                // path: 'board',
                index: true,
                element: <Board/>
            },
            {
                path: 'about',
                element: <About/>
            }
        ]
    },
    {
        path: '/login',
        element: <Login/>
    },
    {
        path: '/article/:id/:name',
        element: <Article/>
    },
    {
        path: '*',
        element: <NotFound/>
    }
])

export default router

效果如下:

image

 

5、俩种路由模式

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

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

之前讲过createBrowserRouter,现在来演示createHashRouter,直接替换即可

import Login from '../page/Login'
import Article from '../page/Article'
import Layout from '../page/Layout'
import Board from '../page/Board'
import About from '../page/About'
import NotFound from '../page/NotFound'
import { createBrowserRouter,createHashRouter } from 'react-router-dom'

const router = createHashRouter([
    {
        path: '/',
        element: <Layout/>,
        children: [
            {
                // path: 'board',
                index: true,
                element: <Board/>
            },
            {
                path: 'about',
                element: <About/>
            }
        ]
    },
    {
        path: '/login',
        element: <Login/>
    },
    {
        path: '/article/:id/:name',
        element: <Article/>
    },
    {
        path: '*',
        element: <NotFound/>
    }
])

export default router

效果如下:

image

 

posted on 2026-09-17 11:19  周文豪  阅读(5)  评论(0)    收藏  举报