React-Router学习笔记

804 阅读5分钟

1.版本区分

react-router有两个版本,一个叫react-router,另一个叫react-router-dom。下面讲一下这两个路由的区别:

react-router:

  • 这是react-router的核心包,同样能提供路由功能。
  • 平台无关 的,意味着可以用于 WebReact NativeNode.js 等不同平台。
  • 如果你要做的是 Web 应用以外的项目(例如 React Native 或其他环境),就应该使用这个包。

react-router-dom:

  • 这是 react-router 的 Web 特定实现,它依赖于浏览器的 DOM API,专门为 Web 应用提供路由支持。
  • 如果你是做 Web 项目,那么应该使用 react-router-dom,它包括了 react-router 的核心功能,并提供了 DOM 特定的功能(如 <BrowserRouter><Link> 等)。
  • react-router-dom 是最常用于 Web 项目的选择。

2.安装react-router-dom

# NPM
npm install react-router-dom

# PNPM
pnpm add react-router-dom

3.createBrowserRouter

这是React Router v6 的一个新特性。跟vue-router很相似,换句话说就是用数组包对象的方式配置路由规则。

4.路由配置

首先,跟vue项目一样在src目录下创建router/index.jsx文件结构。

下面是:index.jsx

import { createBrowserRouter } from 'react-router-dom'
import Home from '../Home'
import About from '../About'

// 创建路由实例
const router = createBrowserRouter([
  {
    path: '/home',
    element: <Home />
  },
  {
    path: '/about',
    element: <About />
  }
])

// 导出路由实例
export default router

main.jsx中进行注册:

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'

// RouterProvider用来注册路由
import { RouterProvider } from 'react-router-dom'
// 导入刚才导出的路由实例
import router from './router'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    {/* 进行注册 */}
    <RouterProvider router={router}></RouterProvider>
  </StrictMode>
)

然后就可以导航了:

image.png

image.png

5.路由导航(跳转)

有两种导航方式:

  1. 声明式导航
  2. 编程式导航

声明式导航

这个几乎跟vue一模一样,Link相当于vue中的router-link

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

export default function Home() {
  return (
    <div className='home'>
      <h1>这是Home页</h1>

      {/* 声明式导航 */ }
      <Link to='/about'>跳转到About页</Link>
    </div>
  )
}

编程式导航

这个也很简单,跟vue中的router.push很相似。
需要从react-router-dom中导入useNavigate Hook。

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

export default function About() {
  const navigate = useNavigate()

  return (
    <div className='about'>
      <h1>这是About页</h1>

      {/* 编程式导航 */ }
      <button onClick={ () => navigate('/home') }>跳转到Home页</button>
    </div>
  )
}

6.路由传参

路由传参分为两种:

  1. searchParams传参
  2. params传参

searchParams传参

下面Home.jsx传递参数:

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

export default function Home() {
  const navigate = useNavigate()

  return (
    <div className='home'>
      <h1>这是Home页</h1>

      {/* 声明式导航 */ }
      <button onClick={()=>navigate('/about?id=007&name=akbar')}>跳转到About页</button>
    </div>
  )
}

也可以使用声明式导航传参:

image.png

下面用About.jsx接受参数:
接受参数的时候需要从需要从react-router-dom中导入useSearchParams Hook。

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

export default function About() {
  const [params] = useSearchParams()
  const id = params.get('id')
  const name = params.get('name')

  return (
    <div className='about'>
      <h1>这是About页</h1>

      <p>id: { id }</p>
      <p>name: { name }</p>
    </div>
  )
}

小知识点
const [params] = useSearchParams(),这里的params代表原生的web api URLSearchParams对象。
URLSearchParams 对象提供了一个 get 方法,用于获取特定的查询参数值。这个方法接受一个查询参数的名称作为参数,并返回该参数的值。

效果图:

image.png

params传参

params传参是用article/:id这种方式传递数据,比如这里的id。

下面是ArticleList.jsx

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

export default function ArticleList() {
  const navigate = useNavigate()

  return (
    <div className='article-list'>
      <h1>文章列表</h1>

      {/* 通过params的方式传递文章id */}
      <button onClick={ () => navigate('/articlePreview/453')}>传递文章id453</button>
    </div>
  )
}

同样也可以使用声明式传参的方式传递参数

image.png

下面是ArticlePreview.jsx
这里需要用到useNavigate Hook.

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

export default function ArticlePreview() {
  const params = useParams()
  const articleId = params.id

  return (
    <div className='article-preview'>
      <h1>文章预览</h1>
      <p>接收到的文章id { articleId }</p>
    </div>
  )
}

然后在路由配置文件index.jsx进行配置:

import { createBrowserRouter } from 'react-router-dom'
import ArticlePreview from '../ArticlePreview'
import ArticleList from '../ArticleList'

const router = createBrowserRouter([
  {
  // 这里的:id就是要接受到的参数
    path: '/articlePreview/:id',
    element: <ArticlePreview />
  },
  {
    path: 'articleList',
    element: <ArticleList />
  }
])

export default router

效果图:

image.png

image.png

7.嵌套路由

嵌套路由也跟vue-router非常相似,嵌套路由的路由出口时<Outlet />

下面模拟一个管理系统页面,演示路由嵌套:

image.png 还有Sidebar.jsx,这个我暂时不知道放到哪个文件夹,vue项目的话可以放到component目录下。

1.Layout.jsx:

import { Outlet } from 'react-router-dom'
import Sidebar from '../Sidebar'

export default function Layout() {
  return (
    <div className='layout'>
      <Sidebar />

      <main className='main'>
        {/* Outlet是路由出口,相当于vue中的router-view */ }
        <Outlet />
      </main>
    </div>
  )
}

2.Sidebar.jsx:

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

export default function Sidebar() {
  return (
    <aside className='sidebar'>
      <ul>
        <NavLink
          to='/'
          className={ ({ isActive }) => isActive ? 'active' : '' }
        >
          <li>Home</li>
        </NavLink>

        <NavLink
          to='/about' className={ ({ isActive }) => isActive ? 'active' : '' }
        >
          <li>About</li>
        </NavLink>
      </ul>
    </aside>
  )
}

为了实现路由高亮,我这里使用了<NavLink>,下面讲一下<NavLink><Link>的区别:

NavLinkLink 都是 react-router-dom 提供的组件,用于在 React 应用中实现页面之间的导航。它们的作用非常相似,但也有一些关键的区别,适用于不同的场景。

Link组件:
Link 是用于创建页面间导航的基本组件。当你需要在页面内跳转到另一个路由时(没有路由高亮需求时),可以使用 Link 来替代传统的 HTML <a> 标签。

NavLink组件:
NavLinkLink 的增强版,主要用于处理路由的激活状态。当一个链接指向的路由匹配当前 URL 时,NavLink 会自动为这个链接添加一个 active 类(或者自定义的类名),通常用于高亮当前活动的链接。
NavLinkclassName 属性可以接受一个函数,该函数接收一个 对象类型的参数,这个对象中我们可以解构出isActive 参数,isActive 是一个布尔值,表示该链接是否是当前激活状态。

image.png

然后再路由配置文件index.jsx中进行配置:

import { createBrowserRouter } from 'react-router-dom'
import Home from '../page/Home'
import About from '../page/About'
import Layout from '../layout/Layout'

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      {
        // 这里不需要给Home组件指定路径,直接写index就可以,然后Home组件的路径就变成'/'
        // index:true 跟vue-router中的redirect很相似
        index: true,
        element: <Home />
      },
      {
        path: '/about',
        element: <About />
      }
    ]
  },
])

export default router

8.404路由配置

首先写一个NotFound.jsx

export default function NotFound() {
  return (
    <div className="not-found-container">
      <h1 className="not-found-heading">404 - Page Not Found</h1>
      <p className="not-found-description">Sorry, the page you are looking for doesn&apos;t exist.</p>
    </div>
  )
}

然后在路由配置文件index.jsx进行配置:

import { createBrowserRouter } from 'react-router-dom'
import Home from '../page/Home'
import About from '../page/About'
import Layout from '../layout/Layout'
import NotFound from '../page/NotFound'

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      {
        index: true,
        element: <Home />
      },
      {
        path: '/about',
        element: <About />
      }
    ]
  },
  {
    // *是通配符,当什么都不匹配的时候跳转到该路由
    path: '*',
    element: <NotFound/>
  }
])

export default router

效果图:

image.png

9.两种路由模式

跟vue-router一样,react-router也有两种路由模式:

  1. createBrowserRouter:history模式
  2. createHashRouter:hash模式