React Router 6详解

1 什么是React-Router?

许多现代网站实际上是由一个页面组成的,它看起来像多个页面,是因为它们包含呈现为单独页面的组件,即单页面+多组件。这些网站通常被称为SPA(single-page web application,单页web应用)。每个单页web应用其实是一系列的 JS 文件,当用户请求网站时,网站返回一整个(或一系列)的 js 文件和 HTML,而当用户在某个页面内点击时,你需要告诉浏览器怎么加载另一个页面地址。单页应用中通常只有一个 index.html 文件的,所以浏览器自带的 <a> 链接并不能用来做单页应用的跳转,因此你需要一个在 React 中的路由实现。

然而 React 框架本身是不带路由功能的,因此如果你需要实现路由功能让用户可以在多个单页应用中跳转的话,就需要使用 React-Router。

React-Router是React体系的一个重要部分,通过管理URL,实现组件的切换和状态的变化。

React-Router经过多个版本的迭代,现在已经到了v6。v4和v5的Router使用差别不大,但v5和v6的差别很大。

2 使用React-Router

step1 安装

React-Router不是React核心库的一部分,因此首先需要将此库安装到你的React项目中:

npm install react-router-dom@6

step2 导入核心组件

你需要从 react-router-dom 包中导入 BrowserRouter,Routes,Route 和 Link:

import { BrowserRouter, Routes, Route,Link } from 'react-router-dom';  

step3 使用BrowserRouter组件包围整个应用

实际上有两种Router:HashRouter和BrowserRouter,前者使用URL的哈希值实现,推荐使用后者,使用H5的history api实现,当你的用户前进后退时,history 这个库会记住用户的历史记录,这样需要跳转时可以直接操作。

Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件。

因此,BrowserRouter组件需要包裹整个应用,渲染的所有内容都要放入 <BrowserRouter> 元素内。

// index.js
ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>, 
    document.getElementById('root')
)

// 或者直接在App组件里包裹整个JSX
//App.js
import { BrowserRouter, Link, Routes, Route } from "react-router-dom";
function App() {
  return (
    //声明使用非hash模式的路由
    <BrowserRouter>
     ...
    </BrowserRouter>
  );
}

step4 添加Link标签

Link标签用于指定跳转,使用to属性指定路由地址,表示要跳转到哪儿去。to属性会被渲染成a标签的href属性。

<Link to="/">首页</Link>

这行代码被渲染成原生JavaScript的a标签元素:

<a href="/">首页</a>

我们在App.js中增加该标签的使用:

function App() {
  return (
    //声明使用非hash模式的路由
    <BrowserRouter>
    {/* 指定跳转 */}
      <Link to="/">首页</Link>
      <Link to="/about">关于</Link>
    </BrowserRouter>
  );
}

step5 路由映射配置(Routes和Route)

  • Routes组件:
    • 用来包裹所有的Route标签,在其中匹配一个路由。React-Router6.x不允许Router组件单独存在。(否则会报错:A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.)
    • 如果不使用该组件,当路由中出现了2个及以上的path同时匹配的情况,将会渲染这多个页面。如果想要只渲染path第一个匹配上的组件的话,那么我们可以使用该组件来解决。
    • 注意:React-Router5.x采用的是Switch组件,6.x改用Routes组件
  • Route组件:
    • 用于路径的配置,需指明两个属性path和element
    • path属性:用于设置匹配到的路径
    • element属性:匹配路径应渲染的组件
    • 注意:React-Router6不再支持5.x中的component和exact属性
function App() {
  return (
    //声明使用非hash模式的路由
    <BrowserRouter>
      {/* 指定跳转 */}
      <Link to="/">首页</Link>
      <Link to="/about">关于</Link>
      <Routes>
        {/* 指定路径和组件的对应关系  */}
        <Route path="/" element={<Home />}></Route>
        <Route path="/about" element={<About />}></Route>
      </Routes>
    </BrowserRouter>
  );
}
写到这里,我们其实已经完成了一个基本的路由功能,对于绝大多数可以公开访问的网站,差不多就已经完结。但有时,你可能希望知道用户所在的路径,来做一些对应显示和特殊逻辑处理,比如你需要让用户鉴权后才能访问某个路径,那么你需要继续读一下后文几个章节。

3 React Router6中引入的hooks

3.1 useLocation 获取当前页路径

在React Router6中,提供了一个hook,专门用来获取当前路径。比如我们希望当用户跳转到/about页面时会显示用户现在的位置、从哪个页面跳转过来。

首先需要导入useLocation这个钩子,然后仿照如下代码就可以获得当前位置。

import { useLocation } from "react-router-dom";

const About = () => {
  const location = useLocation();
  const { from, pathname } = location;
  return (
    <>
      now you are in {pathname}, and you are from {from} page
    </>
  );
};
export default About;

 3.2 useNavigate 实现页面跳转

首先需要导入useNavigate这个hook,调用这个hook,他返回一个函数,这个函数可以控制跳转到哪个页面。

import { useNavigate } from "react-router-dom";

const Login = () => {
  const navigate = useNavigate();
  return (
    <>
      login
      <button
        onClick={() => {
          navigate("/about");
        }}
      >
        跳转到关于页面
      </button>
    </>
  );
};
export default Login;

 4 嵌套路由

现在我们希望页面存在一级路由:/—>首页,/login—>登陆页面;然后在首页中实现二级路由:/board—>看板,/article—>文章。(注意:常用Layout作为一级路由组件)

我们已经在App.js中实现了一级路由的配置:

import Home from "./Home.js";
import Login from "./Login.js";

//进行路由配置
import { BrowserRouter, Link, Routes, Route } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />}></Route>
        <Route path="/login" element={<Login />}></Route>
      </Routes>
    </BrowserRouter>
  );
}

export default App;

现在开始配置二级路由,需要:

  1. 在App组件中定义路由嵌套关系
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />}>
          <Route path="board" element={<Board />}></Route>
          <Route path="article" element={<Article />}></Route>
        </Route>
        <Route path="/login" element={<Login />}></Route>
      </Routes>
    </BrowserRouter>
  );
}

  2. 在一级路由组件中使用 Outlet 组件添加二级路由出口,比如我这里的一级组件是/,即Home页面

import { Outlet } from "react-router-dom";

const Home = () => {
  return (
    <>
      home page;
      <Outlet />
    </>
  );
};
export default Home;

5 默认显式二级路由

浏览器首次加载页面时显示的路径都为/,有些情况下我们希望可以默认展示二级路由,如展示/board界面。这时需要去掉原本的Route标签中的path属性,改为添加index属性。

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />}>
          <Route path="board" element={<Board />}></Route>
          <Route index element={<Article />}></Route>
        </Route>
        <Route path="/login" element={<Login />}></Route>
      </Routes>
    </BrowserRouter>
  );
}

6 集中式路由配置

集中式路由配置,就是用一个数组统一把所有的路由对应关系写好,替换本来的Routes组件。

import { BrowserRouter, Routes, Route, useRoutes } from 'react-router-dom'

import Layout from './pages/Layout'
import Board from './pages/Board'
import Article from './pages/Article'
import NotFound from './pages/NotFound'

// 1. 准备一个路由数组 数组中定义所有的路由对应关系
const routesList = [
  {
    path: '/',
    element: <Layout />,
    children: [
      {
        element: <Board />,
        index: true, // index设置为true 变成默认的二级路由
      },
      {
        path: 'article',
        element: <Article />,
      },
    ],
  },
  // 增加n个路由对应关系
  {
    path: '*',
    element: <NotFound />,
  },
]

// 2. 使用useRoutes方法传入routesList生成Routes组件
function WrapperRoutes() {
  let element = useRoutes(routesList)
  return element
}

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        {/* 3. 替换之前的Routes组件 */}
        <WrapperRoutes />
      </BrowserRouter>
    </div>
  )
}

export default App

 

 

 
 

 

 

 
posted @ 2023-05-29 00:32  设德兰  阅读(454)  评论(0)    收藏  举报