React-Router6学习

60 阅读5分钟

为什么

一般来说,web系统需要多个页面,如果是单个页面的话,太复杂。这就像所有逻辑写在一个函数中,维护困难。那多页面就需要用路由来管理。路由是个通用概念,可以理解为网址。但是是业务上的页面,从技术上还是react的组件。

是什么

React Router 是一个流行的用于构建单页应用程序的路由库。它提供了一组组件,可以帮助我们在 React 应用中实现页面间的导航和路由管理。本文档将介绍 React Router 的使用方法和常见的功能。

怎么用

安装

首先,我们需要使用 npm 或者 yarn 来安装 React Router:

$ npm install react-router-dom
# 或者
$ yarn add react-router-dom

基本用法

BrowserRouter

在你的应用中引入 React Router,然后使用 BrowserRouter 组件包裹你的应用根组件:

import { BrowserRouter } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      {/* Your app code here */}
    </BrowserRouter>
  );
}

Route

接下来,你可以使用 Route 组件来定义路由规则和对应的组件:

import { Route } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <Route path="/" exact component={Home} />
      <Route path="/about" component={About} />
    </BrowserRouter>
  );
}

在上面的示例中,我们定义了两个路由规则:

  • / 路径对应的组件是 Home
  • /about 路径对应的组件是 About 当用户访问不同的路径时,React Router 将会渲染对应的组件。

嵌套路由

React Router 还支持嵌套路由,即在一个组件中定义子路由规则。

import { BrowserRouterRoutesRoute } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users" element={<Users />}>
          <Route path="/" element={<UserList />} />
          <Route path=":id" element={<UserProfile />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

在上面的示例中,我们定义了三个顶层路由:/、/about 和 /users。其中,/users 路径下又有两个子路由:/ 和 /:id。当用户访问不同的路径时,React Router v6 会根据路由配置自动匹配并渲染相应的组件。

注意,在嵌套路由中,父级路由组件(如 /users)需要在其 element 属性中设置一个组件,以便为嵌套的子路由提供一个渲染容器。

此外,你也可以使用 Outlet 组件来渲染嵌套的子路由:

import { BrowserRouterRoutesRouteOutlet } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users">
          <Route index element={<UserList />} />
          <Route path=":id" element={<UserProfile />} />
          <Outlet />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

在上面的示例中,我们使用 Outlet 组件来渲染嵌套的子路由。<Outlet /> 会根据访问的 URL 渲染匹配的路由组件。

路由参数

有时候我们需要从 URL 中提取参数,以便在组件中使用。React Router 提供了 useParams 钩子来实现这个功能。

import { useParams } from 'react-router-dom';
function User() {
  const { id } = useParams();
  return <div>User ID: {id}</div>;
}

在上面的例子中,我们定义了一个 /user/:id 的路由规则,其中 :id 表示一个动态的参数。当用户访问 /user/123 时,useParams 钩子会返回 { id: '123' }

路由跳转

React Router 提供了一些组件来实现导航功能,比如链接 (Link) 和重定向 (Redirect)。

import { LinkRedirect } from 'react-router-dom';
function Navigation() {
  return (
    <div>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
      <Redirect to="/login" />
    </div>
  );
}

编程式导航

当使用 React Router 进行编程式导航时,我们可以使用 history 对象来实现。history 对象提供了一些方法,可以在代码中进行导航操作。 首先,我们需要使用 useHistory 钩子来获取 history 对象:

import { useHistory } from 'react-router-dom';
function MyComponent() {
  const history = useHistory();
  // 导航到指定路径
  const navigateTo = (path) => {
    history.push(path);
  };
  return (
    <div>
      <button onClick={() => navigateTo('/about')}>Go to About</button>
    </div>
  );
}

在上面的例子中,我们使用 useHistory 钩子获取了 history 对象,并定义了一个 navigateTo 函数,该函数接受一个路径参数,并通过 history.push() 方法将用户导航到指定路径。 我们还可以使用 history.replace() 方法进行替换式导航,该方法不会在浏览器历史记录中创建新的条目

import { useHistory } from 'react-router-dom';
function MyComponent() {
  const history = useHistory();
  // 替换当前路径
  const replacePath = (path) => {
    history.replace(path);
  };
  return (
    <div>
      <button onClick={() => replacePath('/contact')}>Go to Contact</button>
    </div>
  );
}

除了使用 push 和 replace 方法导航之外,我们还可以使用其他方法来控制浏览器历史记录,比如 go、goBack 和 goForward:

import { useHistory } from 'react-router-dom';
function MyComponent() {
  const history = useHistory();
  // 后退
  const goBack = () => {
    history.goBack();
  };

  // 前进
  const goForward = () => {
    history.goForward();
  };

  // 跳转到指定历史记录位置
  const goTo = (n) => {
    history.go(n);
  };

  return (
    <div>
      <button onClick={goBack}>Go Back</button>
      <button onClick={goForward}>Go Forward</button>
      <button onClick={() => goTo(-2)}>Go Back 2 steps</button>
    </div>
  );
}

通过使用这些方法,我们可以在 React 应用中进行编程式导航,根据需要控制用户的浏览器行为。

路由守卫

当使用 React Router 构建应用程序时,有时我们需要在导航发生之前或之后执行一些逻辑操作。 不同于Vue-Router,React Router 没有提供相关的回调和方法。 得在应用中,自己实现。比如before场景:

import { Route, useHistory } from 'react-router-dom';
const MyComponent = () => {
  const history = useHistory();
  const beforeGuard = () => {
    // 在导航之前执行的逻辑
    if (!isLoggedIn) {
      // 如果用户未登录,则跳转到登录页面
      history.push('/login');
    }
    retun <User />;
  };
  return (
    <Route path="/profile" render={beforeGuard} />
  );
}

after场景,可以在 componentDidMount 或者 useEffect 中实现;leave场景,可以在componentWillUnmount 或者 useEffect 中实现。

useRoutes

useRoutes是和Route 组件功能相同的官方hook。Route 组件使用元素定义路由和组件,useRoutes使用JavaScript对象来定义和管理路由。

假设我们要设计一个博客系统,涉及到的页面及其路由如下:demo和代码地址

页面路由Layout
首页/MainLayout
登录/register
注册/login
404
管理页面我的博客/manage/listManageLayout
收藏博客/manage/star
博客回收站/manage/trash
博客详情编辑博客/blog/edit/:idBlogLayout
博客统计/blog/stat/:id

使用如下:

首先,我们定义路由管理文件router.js:

import { createBrowserRouter } from "react-router-dom";
const router = createBrowserRouter([
  {
    // 根路由
    path"/",
    element<MainLayout />,
    children: [
      {
            path"/",
            element<Home />
      },
      {
        path"login",
        element<Login />
      },
      {
        path"register",
        element<Register />
      },
      {
        path"manage",
        element<ManageLayout />,
        children: [
          {
            // path: "list",
            // 这个属性表示默认路由,写了这个就不能写path属性
            indextrue,
            element<List />
          },
          {
            path"star",
            element<Star />
          },
          {
            path"trash",
            element<Trash />
          }
        ]
      },
      {
        path"*",
        element<NotFound />
      }
    ]
  },
  {
    path"blog",
    element<BlogLayout />,
    children: [
      {
        path"edit/:blogId",
        element<EditBlog />
      },
      {
        path"stat/:blogId",
        element<BlogStat />
      }
    ]
  }
]);
export default router;

在上面的示例中,routeConfig 数组中的每个对象都包含 path 和 element 属性,分别表示路径和要渲染的组件。如果有嵌套路由,则可以在对应的对象中使用 children 属性来定义子路由。

注意:index: true 和 path: "*"

  • index: true 属性表示默认路由,写了这个就不能写path属性
  • path: "*" 表示所有匹配,没有命中任何规则时显示的组件,一般用来处理错误路由
  • Outlet 其实就是占位,类似于vue中的slot或者router-view 然后,我们在应用入口中引入router:
import "./styles.css";
import { RouterProvider } from "react-router-dom";
import router from "./router";
export default function App() {
  return (
    <div className="App">
      <RouterProvider router={router} />
    </div>
  );
}

参考:

  1. 官网
  2. 示例:地址