Introduction to the

The React Router library contains three different NPM packages, each of which has a different purpose.

  • React-router: A core library that contains most of the core functions of the React Router, including the routing matching algorithm and most of the core components and hooks.
  • React-router-dom: A routing package for the React application that includes everything about the React-Router and adds DOM-specific apis, including BrowserRouter, HashRouter, and Link.
  • React-router-native: Used to develop react Native applications, including all the contents of the React-Router, and adding some React Native specific apis, including NativeRouter and Link.

version

The following V5 is listed from all versions of 5.1.2. There are many alpha and beta minor versions of V6 not listed.

The new project currently uses 6.0.2, while the old project used 5.1.2.

react-router-dom NPM address

version downloads Release Date (comparison date 2022.1.14)
6.2.1 818595 A month ago
6.0.2 464961 2 months ago
6.0.0 5540 2 months ago
5.3.0 1612985 Four months ago
5.2.1 68038 Five months ago
6.0.0 – beta. 0 62966 Two years ago
5.2.0 1734184 Two years ago
6.0.0 – alpha. 0 7 Two years ago
5.1.2 462691 Two years ago

Compared to V5, the packaged package size is reduced from 20.8K to 10.8K. Package analysis website

The installation

/ / NPM installation
npm install react-router-dom@6

/ / yarn installation
yarn add react-router-dom@6
Copy the code

Enable the global routing mode

Two common routing modes are available for global routing: HashRouter and BrowserRouter are hash and History modes, respectively.

USES BrowserRouter:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>.document.getElementById("root"));Copy the code

App.jsx Sets the route

import './App.css';
import { Routes, Route, Link } from "react-router-dom"
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Routes>
          <Route path="/" element={<Home />} ></Route>
          <Route path="/about" element={<About />} ></Route>
        </Routes>
      </header>
    </div>
  );
}
function Home() {
  return <div>
    <main>
      <h2>Welcome to the homepage</h2>
    </main>
    <nav>
      <Link to="/about">about</Link>
    </nav>
  </div>
}
function About() {
  return <div>
    <main>
      <h2>Welcome to the about page</h2>
    </main>
    <nav>
      <ol>
        <Link to="/">home</Link>
        <Link to="/about">about</Link>
      </ol>
 
    </nav>
  </div>
}
export default App;

Copy the code

Writing in the front

If you’re just starting out with React Router, or if you want to try v6 with a new application, seeGetting started guide.

The following describes the new features compared to React Router V5 and how to make a quick migration.

Preparing for the Upgrade

1. Upgrade to React V16.8

React Router V6 makes extensive use of React hooks, so you need to use React 16.8 or later before attempting to upgrade to React Router V6. The good news is that React Router V5 is compatible with React >= 15, so if you’re using V5 (or V4), you should be able to upgrade React without touching any Router code.

2. Upgrade to React Router V5.1 (optional)

Switching to React Router V6 will be easier if you upgrade to V5.1 first. Because in V5.1, enhancements to element handling were released, this will help smooth the transition to V6. Instead of using props, use regular elements everywhere and use hooks to access the internal state of the router.

Upgrade to React Router v6

  • Let me rename it to.
  • New feature changes.
  • Nested routines have been made easier.
  • Use enavigate instead of useHistory.
  • The new hook useRoutes replaces react-router-config.

1. <Switch>rename<Routes>

React Router V6 introduces a Routes component that is similar to the previous Switch but more powerful. It includes functions such as relative routing and linking, automatic routing ranking, nested routing and layout.

// v5
<Switch>
    <Route exact path="/"><Home /></Route>
    <Route path="/profile"><Profile /></Route>
</Switch>
 
 
// v6
<Routes>
    <Route path="/" element={<Home />} / ><Route path="profile/*" element={<Profile />} / ></Routes>

Copy the code

2. <Route>New feature changes

Route is responsible for rendering the React component’s UI. Two attributes are used in V6:

  • Path: matches the URL of the current page.
  • Element: This is added to determine which component to render when routing matches. In V5, we usually used the component property, or render.

Simply put, Component /render is replaced by element

// v5
<Route path=":userId" component={Profile} />
<Route
  path=":userId"
  render={routeProps= > (
    <Profile routeProps={routeProps} animate={true} />)} / >

// v6
<Route path=":userId" element={<Profile />} / >
<Route path=":userId" element={<Profile animate={true} />} / >
Copy the code

3. Nesting routines are simpler

Nesting is common in practical applications, such as the following two pages. The User component is shared, and when switching routes, only the Profile and Posts subcomponents are changed.

In React Router V5, nested routines must be clearly defined. React Router V6 does not. It picks the best element from the React Router library called Outlet to render any matching child elements for a particular route. It works just like the Vue Router.

3.1 Outlet realizes nested routines by

  • Nested routines are implemented in V5 by
// v5
import {
  BrowserRouter,
  Switch,
  Route,
  Link,
  useRouteMatch
} from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/profile" component={Profile} />
      </Switch>
    </BrowserRouter>
  );
}

function Profile() {
  let { path, url } = useRouteMatch();

  return (
    <div>
      <nav>
        <Link to={` ${url} /me`} >My Profile</Link>
      </nav>

      <Switch>
        <Route path={` ${path} /me`} >
          <MyProfile />
        </Route>
        <Route path={` ${path} /:id`} >
          <OthersProfile />
        </Route>
      </Switch>
    </div>
  );
}
Copy the code
  • V6 implementation of nested routines by, you can delete string matching logic. You don’t need any useRouteMatch(). Take advantage of the new API: Outlet (further simplified by taking advantage of useRoutes, discussed in point 5 below).
import { Outlet } from 'react-router-dom';
Copy the code
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} / ><Route path="profile" element={<Profile />} ><Route path=":id" element={<MyProfile />} / ><Route path="me" element={<OthersProfile />} / ></Route>
      </Routes>
    </BrowserRouter>
  );
}

function Profile() {
  return (
    <div>
      <nav>
        <Link to="me">My Profile</Link>
      </nav>{/* Will render directly based on the different routing parameters defined above<MyProfile />or<OthersProfile />* /}<Outlet />
    </div>)}Copy the code

More than 3.2<Routes />

Previously, we could only use one Routes in the React App. But now we can use multiple routes in the React App, which will help us manage multiple application logic based on different routes.

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

function Dashboard() {
  return (
    <div>
      <p>Look, more routes!</p>
      <Routes>
        <Route path="/" element={<DashboardGraphs />} / ><Route path="invoices" element={<InvoiceList />} / ></Routes>
    </div>
  );
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} / ><Route path="dashboard/*" element={<Dashboard />} / ></Routes>
  );
}
Copy the code

4. Use enavigate instead of useHistory

From being clear to being blind…

// v5
import { useHistory } from 'react-router-dom';

function MyButton() {
  let history = useHistory();
  function handleClick() {
    history.push('/home');
  };
  return <button onClick={handleClick}>Submit</button>;
};
Copy the code

Now history.push() will be replaced with navigation()

// v6
import { useNavigate } from 'react-router-dom';

function MyButton() {
  let navigate = useNavigate();
  function handleClick() {
    navigate('/home');
  };
  return <button onClick={handleClick}>Submit</button>;
};
Copy the code

The use of history will also be replaced with:

// v5
history.push('/home');
history.replace('/home');

// v6
navigate('/home');
navigate('/home', {replace: true});
Copy the code

5. Replace react-router-config with the new hook useRoutes

This is done with hooks, which are much cleaner than writing the router component directly to the JSX file above

function App() {
  let element = useRoutes([
    { path: '/'.element: <Home /> },
    { path: 'dashboard'.element: <Dashboard /> },
    { path: 'invoices'.element: <Invoices />,
      children: [
        { path: ':id'.element: <Invoice /> },
        { path: 'sent'.element: <SentInvoices />}},// 404 not found
    { path: The '*'.element: <NotFound />}]);return element;
}
Copy the code

The project practice

The following examples are based on useRoutes

In this example, the fullPath attribute is a self-defined unofficial attribute, because when nested routines are created, only relative paths need to be written. The React Router does not use this property to see the full path containing the parent path.

1. The lazy loading

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

/ / lazy loading
const lazyLoad = (path: string) = > {
    const Comp = React.lazy(() = > import(`@page/${path}`))
    return (
        <React.Suspense fallback={<>Loading in...</>} ><Comp />
        </React.Suspense>
    )
}

const routers = [
    {
        name: 'the project'.path: '/'.element: <Backbone />,
        children: [
            {
                name: 'home'.path: 'index/*'.// This attribute is not used in actual route rendering.
                fullPath: '/index'.element: lazyLoad('IndexPage')}]]const Index = () = > useRoutes(routers)

export default Index
Copy the code

2. Index Route: indicates the default sub-route

Set the rendering component for nested routines that match only parent paths. When nested routines have multiple child routes but cannot determine which child route to render by default, you can add index attribute to specify the default route.

The index route differs from other routes in that it has no path attribute and shares the same path with the parent route.

For example, the following route sets up two invoices, namely /foo/invoices and /foo/activity. But when the page accesses /foo directly, the page doesn’t know how to render. In this case, you can set the default display to the invoices through index.

const routers = [
    {
        name: 'the project'.path: '/foo'.element: <Layout />,
        children: [
            // If only the parent route is matched, set index to true and do not specify path
            { index: true.element: lazyLoad('Invoices')}, {name: 'home'.path: 'invoices'.element: lazyLoad('Invoices')}, {name: 'about'.path: 'activity'.element: lazyLoad('Activity'}]}]Copy the code

3. 404

Deprecated Redirect in V5

  // V5 is deprecated
   const routers = [
  		{ path: 'home'.redirectTo: '/'}]// 404 can be written like this
  const routers = [
     {
          name: '404'.path: The '*'.element: <NoMatch />}]Copy the code

4. Dynamic routes

We often need to map all the routes that a pattern matches to the same component. For example, the News details page, corresponding to different News, corresponding to the News component, the path may be News /1, News /2… . The number 1 indicates the ID of the news. This is a dynamic change.

  • Dynamic path parameters start with a colon
const routers = [
		{
        name: 'Notice Details Page'.// Dynamic path parameters start with a colon
        path: 'noticeDetail/:id'.fullPath: '/noticeDetail'.element: lazyLoad('NoticeDetail')}, {name: 'Help Centre Details Page'.path: 'helpCenterDetail/:fid/:sid'.fullPath: '/helpCenterDetail'.element: lazyLoad('HelpCenterDetail')}]Copy the code
  • UseParams Is used by components to obtain dynamic path parameters

    For example, in the example above, there are two dynamic parameters fid and SID in the HelpCenterDetail component:

import { useParams } from 'react-router-dom'
const { fid, sid } = useParams()
Copy the code

5. Route wildcard

The following wildcard numbers are supported. Note: * is used only after /, not in the middle of the actual path

/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
Copy the code

The following are not supported in V6

/users/:id?
/tweets/:id(\d+)
/files/*/cat.jpg
/files-*
Copy the code

6. Url search parameters

Use of useSearchParams.

For example: http://URL/user? Id =111, obtain the value of id

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

const [searchParams, setSearchParams] = useSearchParams()

// Get parameters
searchParams.get('id')

// Check whether the parameter exists
searchParams.has('id')

// You can also use the set method to change the route within the page
setSearchParams({"id":2})
Copy the code

7. withRouter

V6 no longer provides withRouter, slightly cratered.

Official explanation: This problem usually arises when you use a React class component that does not support hooks. In React Router V6, we fully accepted the hooks and used them to share the internal state of all routers. But that doesn’t mean you can’t use a router. Assuming you can actually use hooks (you’re using React 16.8+), you just need a wrapper.

import {
  useLocation,
  useNavigate,
  useParams
} from "react-router-dom";

function withRouter(Component) {
  function ComponentWithRouterProp(props) {
    let location = useLocation();
    let navigate = useNavigate();
    let params = useParams();
    return (
      <Component
        {. props}
        router={{ location.navigate.params}} / >
    );
  }

  return ComponentWithRouterProp;
}
Copy the code

Complete examples in the project

import { useRoutes } from 'react-router-dom'
import Backbone from '.. /layouts/Backbone'
import InfoPage from '.. /pages/InfoPage/index'
import DataCenterPage from '.. /pages/DataCenterPage/index'
import NoMatch from './NoMatch'

/ / lazy loading
const lazyLoad = (path: string) = > {
    const Comp = React.lazy(() = > import(`@page/${path}`))
    return (
        <React.Suspense fallback={<>Loading in...</>} ><Comp />
        </React.Suspense>
    )
}

const routers = [
    {
        name: 'the project'.path: '/'.element: <Backbone />,
        children: [
            // Matches only the parent route
            { index: true.fullPath: '/'.element: lazyLoad('IndexPage')}, {name: 'home'.path: 'index/*'.fullPath: '/index'.element: lazyLoad('IndexPage')}, {name: 'Message center'.path: 'info/'.// element: lazyLoad('InfoPage'),
                element: <InfoPage />,
                children: [
                    { index: true.fullPath: '/info'.element: lazyLoad('NoticeList')}, {name: 'notice'.path: 'noticeList'.fullPath: '/info/noticeList'.element: lazyLoad('NoticeList')}, {name: 'Help Center'.path: 'helpCenter'.fullPath: '/info/helpCenter'.element: lazyLoad('HelpCenter'}]}, {name: 'I want to promote it.'.path: 'activityList/*'.fullPath: '/activityList'.element: lazyLoad('ActivityList')}, {name: 'Data center'.path: 'data/'.// element: lazyLoad('InfoPage'),
                element: <DataCenterPage />,
                children: [
                    { index: true.fullPath: '/data'.element: lazyLoad('Order')}, {name: 'Order Query'.path: 'order'.fullPath: '/data/order'.element: lazyLoad('Order')}, {name: 'Revenue Query'.path: 'reward'.fullPath: '/data/reward'.element: lazyLoad('Reward')}, {name: 'Settlement Enquiry'.path: 'settlement'.fullPath: '/data/settlement'.element: lazyLoad('Settlement'}]}]}, {name: 'Notice Details Page'.// Dynamic routing
        path: 'noticeDetail/:id'.fullPath: '/noticeDetail'.element: lazyLoad('NoticeDetail')}, {name: 'Help Centre Details Page'.path: 'helpCenterDetail/:fid/:sid'.fullPath: '/helpCenterDetail'.element: lazyLoad('HelpCenterDetail')}, {name: 'Personal Registration Page'.path: 'register/person'.fullPath: '/register/person'.element: lazyLoad('PersonBaseInfo')}, {name: '404'.path: The '*'.element: <NoMatch />}]const Index = () = > useRoutes(routers)

export default Index
Copy the code

Common routing components and hooks

Complete API: reactrouter.com/docs/en/v6/…

Component name role instructions
<Routers> A set of routing Instead of the original<Switch>, all child routes are represented by the basic Router children
<Router> Based on the routing The Router can be nested, addressing the rigid pattern of the original V5
<Link> Navigation components Skip to the actual page
<Outlet/> Adaptive rendering components The component is automatically selected based on the actual ROUTE URL, which is mainly used for nested routes, similar to Vue Router<router-view>
Hooks, role instructions
useParams Return current parameter Read parameters based on the path
useNavigate Return current route Replace useHistory in V5
useOutlet Returns the element generated based on the route
useLocation Returns the current Location object
useRoutes The same as the Routers, but only used in JS Instead of react — the router config
useSearchParams Matches? In the URL. Search parameters that follow

reference

React Router address: React Router

The React the Router documentation: reactrouter.com/docs/en/v6

Complete API: reactrouter.com/docs/en/v6/…

react-router-dom: NPM address

Reference blog: blog.csdn.net/weixin_4090…

zhuanlan.zhihu.com/p/191419879

www.jianshu.com/p/03234215a…

Blog.csdn.net/zjjcchina/a…

Package size analysis at bundlephobia.com/