React is a JavaScript library for building user interfaces. It’s a single page application (SPA). Single-page applications, as the name suggests, have only one page and no routing navigation mechanism. A routing mechanism is often needed to switch between different views without refreshing the entire web page. React-router is a third-party library that extends React to allow multiple page redirects.

Get started with React-Router See this complete guide to getting Started with the React Router (including Router Hooks) at 🛵

In this article, we are not using any scaffolding. Go from zero to one to achieve the effect shown in the following image!

Install dependencies

yarn add react-router-dom

yarn add @types/react-router-dom --dev
Copy the code

Routing Basic Configuration

Let’s first implement a simple route configuration and page jump function

import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

export default function BasicExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        </ul>

        <hr />
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

function About() {
  return (
    <div>
      <h2>About</h2>
    </div>
  );
}

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
    </div>
  );
}
Copy the code

We do this by importing the three components and rendering them in the browser. These three components correspond to three dynamic routes

  • HomeComponent path/
  • AboutComponent path/about
  • DashboardComponent path/dashboard

The Link component is used to switch between pages and does not refresh the entire page. The React Router also saves urls to the browser history 📝, which can be accessed via the browser’s rollback and forward buttons

The

iterates through all < routes > below it and then renders the first component whose path matches the current url.

If

matches the first Route, it will not continue to match. If Route is not added with exact, then the path to in Link contains /, then it will be matched with exact. It can be matched only when the path is completely consistent

Nested routing

In a real front-end scenario, a route would also have its child routes below it – that is, route nesting

For example, /user/login, /user/register exist in the /user directory

So when such a scenario occurs, how should the routing be configured?

Let’s take a look at the React Router official route nesting example

You can find

  • First there is a copy in the outermost componentSwitchPackage routing configuration – included/Subpath page
  • Then, inTopicsThere is one in the componentSwitchPackage routing configuration – included/topicsSubpath page. InTopicsThe component uses the logic of nested routes, which are declared inside the componentSwitchThe routing configuration of the package, which is the subpath corresponding to the current path

Because routing is also a React component, the Switch/Route can be rendered anywhere in the code, including as a child element. This is useful when you need to split your application code into multiple packages

The so-called code code split, is different business code split, the same business code loaded together.

So how to distinguish between the same business and different?

In this case, you can differentiate the split by route and render the sub-route into the split packet (and declare the routing configuration of the Switch packet inside the sub-component). This is very consistent with the idea of code separation, isn’t it? ლ (‘ ◉ ❥ ◉ ` ლ)

Configuration routing

In real development scenarios, we often only need a route configuration file to generate routes and menus to facilitate the management of all routes, which is also consistent with the React UI=F(data) data-driven view idea

The main idea is as follows: The route configuration file serves as a static data store

  • Generated by cyclic traversal<Switch>and<Route>, that is, route configuration
  • The sidebar menu is generated through a loop

Let’s see an example of how to configure the React Router

Sidebar menu

One of the most common left/right layouts – left menu, right content.

How do we do that with the React-Router. All we really need to do is change the layout style of our previous code

The main idea is as follows: The route configuration file serves as a static data store

  • Generated by cyclic traversal<Switch>and<Route>, that is, route configuration
  • The sidebar menu is generated through a loop
  • Modify the CSS style to achieve left and right layout

Let’s take a look at the React Router’s official sidebar menu

React Router + Antd implements the sidebar menu

From the previous example of routing nesting 🌰

const routes = [
  {
    path: "/sandwiches".component: Sandwiches,
  },
  {
    path: "/tacos".// Public layout component
    component: Tacos,
    routes: [{path: "/tacos/bus".component: Bus,
      },
      {
        path: "/tacos/cart".component: Cart,
      },
    ],
  },
];

function Tacos({ routes }) {
  return (
    <div>
      <h2>Tacos</h2>
      <ul>
        <li>
          <Link to="/tacos/bus">Bus</Link>
        </li>
        <li>
          <Link to="/tacos/cart">Cart</Link>
        </li>
      </ul>

      <Switch>
        <Route path="/tacos/bus" component={Bus} />
        <Route path="/tacos/cart" component={Cart} />
      </Switch>
    </div>
  );
}
Copy the code

We found that the corresponding component of/TACOS is mainly used for interface public layout and rendering sub-routing, which should be quickly understood by those who have known Antd Design Pro routing configuration.

So let’s change the code to make our project look more like Antd Design Pro

Layout file

Antd Design Pro has multiple layout files

  • BasicLayout: used for a layout with a home screen
  • UserLayout: Is used to layout the user login/registration interface
  • BlankLayout: Blank layout

The routing file

The true embeddedness is understood by configuration

Rendering the routing

const RouteWithSubRoutes = (routeDatas: menuType[]) = > {
  if (Array.isArray(routeDatas) && routeDatas.length > 0) {
    return routeDatas.map((item) = > {
      const bool = Array.isArray(item.routes) && item.routes.length > 0;
      if (bool) {
        return (
          <Route
            key={item.path}
            path={item.path}
            render={(props)= >Array.isArray(item.routes) && item.routes.length > 0 ? (// Item.layout is BasicLayout, UserLayout, BlankLayout<item.component {. props} >
                  <Switch>
                    <Route exact path={item.path}>
                      <Redirect to={item.routes[0].path} />
                    </Route>{/* if there are multiple levels of routing, render multiple configuration files recursion */} {RouteWithSubRoutes(item.routes)}<Route path="*">
                      <NoMatch />
                    </Route>
                  </Switch>
                </item.component>
              ) : (
                <Redirect
                  to={{
                    pathname: "/user/login",
                    state: { from: props.location}}} / >
              )
            }
          />
        );
      }
      // Render the interface directly when there is only one level of routing
      return (
        <Route path={item.path} key={item.path}>
          <item.component />
        </Route>
      );
    });
  }
  return null;
};
Copy the code

Render sidebar menu

The sidebar menu is displayed only when the user logs in successfully and accesses the home page. That is, display it in BackLayout

const Index: React.FC = (props) = > {
  const handleClick: MenuClickEventHandler = (e) = > {
    console.log("click ", e);
  };
  // Generate the menu recursively
  const generateMenu = (menus: menuType[]) = > {
    return menus.map((item) = > {
      if (Array.isArray(item.routes) && item.routes.length > 0) {
        return (
          <SubMenu key={item.path} icon={<SettingOutlined />} title={item.name}>
            {generateMenu(item.routes)}
          </SubMenu>
        );
      }
      return (
        <Menu.Item key={item.path} icon={<AppstoreOutlined />} ><Link to={item.path}>{item.name}</Link>
        </Menu.Item>
      );
    });
  };

  // Extract the child routes from the routes configuration to render the menu
  const renderMenu = (datas: menuType[]) = > {
    if (
      Array.isArray(datas) &&
      datas.length > 0 &&
      Array.isArray(datas[0].routes) &&
      datas[0].routes.length > 0
    ) {
      const homeMenus = datas[0].routes.filter((item) = > item.path === "/home");
      if (
        Array.isArray(homeMenus) &&
        homeMenus.length > 0 &&
        Array.isArray(homeMenus[0].routes) &&
        homeMenus[0].routes.length > 0
      ) {
        const realHomeMenus = homeMenus[0].routes;
        returngenerateMenu(realHomeMenus); }}return null;
  };

  return (
    <Layout style={{ minHeight: "100vh}} ">
      <Sider collapsible collapsed={false}>
        <div className="logo" />
        <Menu onClick={handleClick} mode="inline" theme="dark">
          {renderMenu(routes)}
        </Menu>
      </Sider>

      <Layout className="site-layout">
        <Header className="site-layout-background" style={{ padding: 0}} / >
        <Content style={{ margin: "16px 0 0 16px}} ">
          <div
            className="site-layout-background"
            style={{ padding: 24.minHeight: 360 }}
          >
            {props.children}
          </div>
        </Content>
        <Footer style={{ textAlign: "center}} ">
          Ant Design ©2023 Created by Ant UED
        </Footer>
      </Layout>
    </Layout>
  );
};

export default Index;
Copy the code

Q&A

Manually refreshing the child page produces a 404

Modify the WebPack configuration of the development environment

const confog = {
  output: {
    publicPath: "/",}};Copy the code

You cannot use React Hooks in if/ loop statements

An error message is displayed. Because the underlying React Hooks are implemented as ordered lists, placing them in if/ loop statements can cause the order of execution to change, resulting in unexpected errors ❎

The last

Here’s a summary of what we’ve done in this article

  • Create a route configuration file manually
  • Routes are generated according to the routing file
  • Generate menus from routing files

There’s actually some knowledge about routing permission verification that’s not covered here, but if you’re interested, please comment in the comments section

Refer to the article

  1. Configuring static Routes
  2. babel-plugin-syntax-dynamic-import
  3. reactrouter-sidebar
  4. ant-design-layout