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
Home
Component path/
About
Component path/about
Dashboard
Component 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 component
Switch
Package routing configuration – included/
Subpath page - Then, in
Topics
There is one in the componentSwitch
Package routing configuration – included/topics
Subpath page. InTopics
The component uses the logic of nested routes, which are declared inside the componentSwitch
The 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 screenUserLayout
: Is used to layout the user login/registration interfaceBlankLayout
: 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
- Configuring static Routes
- babel-plugin-syntax-dynamic-import
- reactrouter-sidebar
- ant-design-layout