An overview of the
React requires the react-Router to build a single-page application. With React-Router, we can establish mappings between routes and components (pages). When switching routes, the matching components (pages) are rendered to their respective locations.
React-router-dom and react-router-native are available in two versions of the react router. React-router-dom is applied to Web applications, and react-router-native is applied to native applications, that is, react-native apps.
This article mainly introduces the specific application of react-router-DOM. All react-routers mentioned in the following are actually react-router-dom.
Use the react – the router
There are plenty of examples of how to use the React -router on the official website. To learn more about the use of react-Router, visit the react-Router website.
The working principle of
HTML 5 introduces in the window. The history. PushState and window history. ReplaceState method, they can add and modify the browser’s history And don’t need to reload the page.
The pushState and replaceState methods must be used together with window. onpopState. Back, window.history.go, and window.history.forward methods can be used to activate a browser history. If the active history is added by pushState or modified by replaceState, the registered PopState event is triggered.
The pushState and replaceState methods do not trigger the popState event.
If the browser does not support pushState or replaceState, we can also add and modify the browser history by using window.location.hash = ‘XXX’ or window.location.replace. Without the need to reload the page.
Hash and window.location.replace must be used together with window.onhashchange. The registered onHashChange event is triggered whenever the hash value of the activated history is different from the hash value of the current URL.
With window.location.replace, if only the hash is changed, the page is not refreshed.
Whenever you modify the hash, the Hashchange event is triggered.
React-router is used to redirect single-page applications based on the above principles.
When you need to jump to a page, add or modify the history using the pushState(replaceState, window.location.hash, window.location.replace) methods, and then rerender the page. The registered popState (Hashchange) event is triggered when a history is activated through the browser’s forward or backward buttons, or through the go, back, forward, and other methods, and the page is rerendered.
The basic flow of react-Router for single page hops is as follows:
-
Start the React application.
Every React application starts with the reactdom. render method.
-
Render the BrowserRouter(HashRouter) component.
In the React Router application, we usually use BrowserRouter or HashRouter. BrowserRouter(HashRouter) is a class component that builds and initializes the component instance during the render phase, and then executes the Render method.
The BrowserRouter(HashRotuer) component instance creates a History object during initialization. The history object is used to jump to the page and provides methods like push, replace, go, back, forward for external use. During the entire rendering process, it is passed to the sub-component – the page component – for use by it via props.
-
Render the Router component.
Once the Render method of the BrowserRouter(HashRouter) component completes, the Router component will be rendered.
The Router component, which is also a class component, builds and initializes the component instance during the render phase, and then executes the Render method.
During initialization of the Router component instance, a state object is defined. The state object has a location property, whose value is an object that stores the current URL information for the application. In addition, popState (hashChange) events are registered to the window object through the history object passed by the parent component -BrowserRouter (HashRouter).
-
Render the Route component.
After the Render method on the Router component completes, the Route component is rendered.
During rendering, the path property of the Route component is compared to the location information passed by the parent – Router component. If it matches, then the page component corresponding to the Route component can be rendered, otherwise not.
-
The React application is started.
-
A page component triggers a page redirect.
When a page component triggers a page jump via push or replace, it adds the url corresponding to the new page to the browser history (or replace history) and triggers the Router component instance to execute the setState method to update the location.
When the setState method is executed on the Router component instance, the update of the Router component is triggered. As a result, the sub-component-Route component is also updated, and the corresponding page component is also updated, thus realizing the page hopping.
-
Move forward or backward to activate the history page.
At this point, the popState (Hashchange) event registered with the Window object is raised. In callback, the URL information for the activation page is retrieved, and the Router component instance is triggered to execute the setState method to update the location.
When the setState method is executed on the Router component instance, the update of the Router component is triggered. As a result, the sub-component-Route component is also updated, and the corresponding page component is also updated, thus realizing the page hopping.
The whole flow chart is roughly as follows:
hash & history
Like the ue-router, the React -router has two modes: hash mode and history mode.
In history mode, BrowserRouter is used and the page URL format is protocol://hostname: port/ XXX/XXX, which is more beautiful. When switching pages, window.location. pathName is changed.
History mode is implemented based on native history-pushState, replaceState, and popState. When we jump to a page using push(replace), we use pushState(replaceState) to add (replace) history to the browser, and then render the corresponding page. When we access the browser’s history through page navigation (forward, backward) or go(back, forward), the PopState event is triggered and the corresponding page is rendered.
If the browser does not support pushState(replaceState), the browser refreshes the page in window.location.assign (window.location.replace) mode.
In hash mode, that is, using HashRouter, the page URL format is protocol://hostname: port/ XXX/XXX /#/ XXX. When switching pages, just change window.location.hash.
Hash mode is implemented by modifying window.location.hash and hashchange. When we do a push jump, we modify window.location.hash directly, add history to the browser, and render the page. When we use replace to jump to a page, we will first build a temporary URL after the hash is modified, and then use this temporary URL to replace the current URL with window.location.replace, and replace the history in the browser. Then render the page. When we access the browser’s history through page navigation (forward, backward) or go(back, forward), the Hashchange event is triggered and the corresponding page is rendered.
Note that using history mode requires server support, adding a candidate resource on the server that covers all cases: if the URL does not match any static resource, the same index.html page should be returned, which is the page on which the application depends, otherwise a 404 exception will occur.
Typically, BrowserRouter is used. If the browser does not support pushState, use HashRouter instead.
Route
During the rendering phase, the Route component compares the Location object (that is, the URL information for the current page) passed from the parent component, the Router, with the Path configuration item. Only if the Route component matches the current URL will the corresponding page component be rendered.
The Route component with no path set matches any URL.
The common ways to use Route are as follows:
-
component
Add a Component attribute to the Route component as follows:
<Route path='/componentA' component={ComponentA} /> Copy the code
In this way, the Route component passes the history object and location object passed by the parent component – Router, and objects generated by the matching process to the page component via props during rendering. This allows history and location to be accessed in the page component via props.
-
render
Add the Render attribute to the Route component as follows:
<Route path="/componentA"render={props => <ComponentA {... props} {... others} />} />Copy the code
As with Component, the Route component passes the history object, location object, and objects generated by the matching process to the page component via props during rendering. This allows history and location to be accessed in the page component via props.
-
Children (function type)
Add a child element of type function to the Router component as follows:
<Route path="/componentC"> {(props) => <ComponentC {... props} ... {others}/>} </Route>Copy the code
As with component and Render, the Route component passes the history object and location object passed by the parent – Router, and objects generated by the matching process to the page component via props. This allows history and location to be accessed in the page component via props.
-
Children (non-functional type)
Add a non-functional child element to the Router component as follows:
<Route path="/componentA"> <ComponentA/> </.Route> Copy the code
Unlike component and render, The Route component cannot pass the history object and location object passed by the parent component-Router and the match object generated by the matching process to the page component through props during rendering. Therefore, history and location are not accessible in the page component.
In addition to passing history, location, and match objects to the page component, you can also pass custom properties. This is critical when using static routing configurations for nested routes.
Note that as long as the Path property of the Route component matches the current page URL, the corresponding page component is rendered.
When using the Route component, there are a few key properties that we need to look at, as follows:
-
path: string | [string]
Required property to match location.pathName. If they match, the Route component and the page component are rendered.
-
exact ? : boolean
It is an optional attribute. The default value is false, indicating that exact matching is not required.
If exact or exact = true is specified, an exact match is required. That is, the path specified by the path attribute must be exactly the same as location.path.
Note that if nested routines are used, the Route component corresponding to the parent page should not be set to an exact match, otherwise nested routines will fail.
-
strict ? : boolean
This attribute is optional. The default value is false, indicating that strict matching is not required.
Strict matching is required if the strict attribute or strict = true is specified. In this case, the path with ‘/’ can only match the location. Pathname with ‘/’.
Such as:
path location.pathname match ? /one /one y /one /one/ n /one /one/two n /one/ /one/ y /one/ /one/two y /one/ /one n Note that if nested routines are used, do not set strict matching when the path attribute value of the Route component corresponding to the parent page is in the format of ‘/ XXXX ‘, otherwise nested routines will fail.
-
sensitive ? : boolean
The default value is false, that is, ignore case.
If you specify sensitive or sensitive = true, case is not ignored.
Switch
With the Route component, as long as the Path attribute matches the pathName of the current page URL, the corresponding Route component and page component are rendered.
If we wrapped the Route component (or Redirect component) with the Switch component, only the first Route component (or Redirect component) matching the location.pathname would be rendered.
The Switch component takes effect after rendering the children(Routes and Redirects). During rendering children, children are iterated over, and each child is matched with location.pathName. If a match is found, the traversal stops immediately and the matching child is returned.
Programmatic navigation
In addition to using the Link component to create an A tag to define navigation links, we can do this by writing code using the History object method that the Router component passes to the page component.
When we use the Route component as a component, render, and function formula component, The Route component passes the history object and location object passed by the parent component-Router and the match object generated by the matching process to the page component through props during rendering. In the page component, programmatic navigation is achieved through props. History.
History is implemented based on window.history and provides the following methods for us to use:
-
Jump to the page in push-push mode;
-
Replace-replace mode jumps to the page;
-
Go – advances or rewinds n pages;
-
GoBack – Back a page;
-
GoForward – forward n pages;
We can also access the URL information of the current page in the presentation component through props. Location or prop.history.location.
The location object has the following attributes:
-
Location. pathName – The path to the current URL;
-
Location. hash – The hash value of the current URL;
-
Location. search – The query part of the current URL;
-
Location. state – custom information passed by the user;
After the Route component matches successfully, a matching object – match will be generated for the page component to use, the main properties are as follows:
-
Url-the pathname passed by the page jump;
-
Path-route Specifies the path configuration item of the component.
-
Params-dynamic path parameter;
<Link to='/user/123' /> <Route path='/user/:id'Component ={User} /> // params-dynamic path parameter {id: 123}Copy the code
hooks
When we use the Route component as a component, render, and function formula component, The Route component passes the history object and location object passed by the parent – Router, and the match object generated by the matching process to the page component for use by the props during rendering.
If the page component is a class component, you must use the above method to use history, location, and match in the page component, but if it is a functional component, you can use the hooks provided with the React Router to do the same.
The React Router provides some hooks for us to use, as follows:
-
useHistory
Gets the History object built by the Router component.
-
useLocation
Obtain the url information corresponding to the current page, such as pathName, hash, search, and state.
-
useParams
Gets dynamic path parameters.
-
useRoutematch
Obtain the route matching object – match.
If path is specified, return the matching result of location. Pathname and the specified path. If path is not specified, return the match object generated during the Route component’s matching operation.
The use of hooks can be learned from:Website – Hooks.
Embedded routines by
Nesting When using React Touter, we can also implement nesting, as illustrated by site-nesting.
Nesting is to use the Route component in the page component. When we switch to a child path, we first render the parent Route component and the page component matching the current location. pathName. After the parent page component is rendered, Render the subroute component and the page component that match the current location.pathname.
Both the parent Route component and the page component are re-rendered (the render method is re-executed), whether the parent Route is switched to a child Route or from a child Route to a parent Route, but the corresponding DOM node is not updated. Whenever you switch to a child Route, both the parent Route component and the page component are re-rendered.
When nested routes are used, do not set exact or strict matching for the parent Route component. Otherwise, nested routes will fail.
Route lazy loading
In actual React applications, route lazy loading is indispensable.
Route lazy loading is based on webpack and other packaging tools to achieve. When a page is dynamically loaded, a Promise object is first built. When the Promise object is initialized, the file corresponding to the lazy page is obtained from the server by dynamically building script elements. When the lazy page file is loaded and executed, the promise object is set to Resolved and the corresponding onFullfilled is triggered. In onFullfilled, render the page that has finished loading.
The whole process is roughly as follows:
-
In the initial rendering, when the lazy loading page is encountered, the corresponding Promise object is constructed and the file corresponding to the lazy loading module is obtained from the server side.
At this point, the state of the Promise object is Pending.
-
Finish the initial render.
For the first rendering, the loading component corresponding to the lazy loading page is rendered as a DOM node.
-
When the lazy page has finished loading, the corresponding Promise object’s state changes to Resolved, triggering the onFullfilled registered.
In onFullfilled, the React update is triggered.
-
After all lazy modules are loaded, start the React update.
At this point, all lazily loaded components have been retrieved. After the React Render and React Commit phases, the page components are rendered as actual DOM nodes.
Route lazy loading mode:
- React.lazy + React.Suspense
// lazyLoad.js
import {lazy, Suspense} from 'react'
export default function (loader, Loading) {
const LazyComponent = lazy(loader)
return function (props) {
returnComponentA = lazyLoad() => import(/*) {componentA = lazyLoad() => import(/*);} webpackChunkName:'component-1'* /'./component-1'), Loading)
Copy the code
- Use the react – loadable
import React from 'react';
import Loadable from 'react-loadable';
export default Loadable({
loader: () = >import(/* webpackChunkName: 'component-1'* /'./component-1'),
loading: Loading
});
Copy the code
Static Route Configuration
In actual React applications, we usually create a separate static Route configuration, routeConfig, and then dynamically create Route components based on this configuration. Usage:
// routeConfig.js
const routes = [{
path: '/one',
conponent: 'One',
routes: [{
path: '/two',
component: 'Two'
}, {
path: '/three',
component: 'Three'}}],... ] <BrowserRouter> <Switch> {routes. Map ((route, i) => ( <Route path={route.path} render={ props => <route.component {... props} routes={route.routes} } /> ))} </Switch> </BrowserRouter> // Onefunction One(props) {
let child
if(props.routes && props.routes.length) { child = <Switch> {routes.map((route, i) => ( <Route path={route.path} render={ props => <route.component {... props} routes={route.routes} } /> ))} </Switch> }return (
<div>
...
{child}
</div>
)
}
Copy the code
The react router provides a react-router-config to configure static routes:
import { renderRoutes } from "react-router-config";
<BrowserRouter>
{renderRoutes(routes)}
</BrowserRouter>
Copy the code
The renderRoutes method is implemented as follows:
import React from "react";
import { Switch, Route } from "react-router";
function renderRoutes(routes, extraProps = {}, switchProps = {}) {
returnroutes ? ( <Switch {... switchProps}> {routes.map((route, i) => ( <Route key={route.key || i} path={route.path} exact={route.exact} strict={route.strict} render={props => route.render ? ( route.render({ ... props, ... extraProps, route: route }) ) : ( <route.component {... props} {... extraProps} route={route} /> ) } /> ))} </Switch> ) : null; }export default renderRoutes;
Copy the code
Contrast the vue – the router
For details about the differences between the React Router and vue Router, see The React Router and Vue Router.
To be continued…