Introduction to react to the router
React-router contains three libraries, react-Router, react-router-dom, and react-router-native. React-router provides the most basic routing functions. In actual use, you can choose to install react-router-dom or react-router-native based on the application environment.
Yarn add react-router-dom or yarn add react-router-nativeCopy the code
The basic use
In React-Router, everything is a component. Router-router, link-link, Route, exclusive Switch, and redirection-Redirect all exist in the form of components
import React from "react";
import { BrowserRouter as Router, Link, Route, Switch } from "react-router-dom";
import HomePage from "./HomePage";
import LoginPage from "./LoginPage";
import UserPage from "./UserPage";
function RouterPage() {
return (
<div>
<h3>RouterPage</h3>
<Router>
<nav>
<Link to="/">Home page</Link> <Link to="/user">The user center</Link>{" "}
<Link to="/login">The login</Link> <Link to="/product/123">goods</Link>
</nav>
<Switch>
<Route path="/" exact component={HomePage} />
<Route path="/user" component={UserPage} />
<Route path="/login" component={LoginPage} />
<Route render={()= > <h3>404 not found</h3>} / ></Switch>
</Router>
</div>
);
}
export default RouterPage;
Copy the code
Route renders content in three ways
Children > Component >render
All three receive the same [route props], including match,location, and history, but children’s match is null if they do not match
The three modes are mutually exclusive and you can only select one of them
children:func
Sometimes, if you want to render something regardless of whether the location matches or not, you can use children, which works exactly the same as render, except that the location will be rendered regardless of whether the location matches or not
render:func
When you render, you’re just calling a function, but it, like component, can access all the route props
component:component
Render only if the location matches
Note: When using Component, Route creates a new React Element with the component you specify and react. createElement. This means that when you provide an inline function, each render creates a new component. This results in not updating an existing component, but simply uninstalling and mounting a new component. Therefore, when using inline rendering of inline functions, use render or children
Excerpt from source code:
BrowserRouter vs. HashRouter
1, HashRouter is the simplest. It does not require server rendering. BrowserRouter requires the server to return different HTML for different urls
BrowserRouter uses the HTML5 history API (pushState, replaceState and PopState events) to synchronize the UI of the page with the URL
3. The HashRouter does not support location.key and location.state. Passing parameters
4. Hash History can run without any server configuration
React-router transmits parameters in three ways
- The first option is to write it in the path parameter of the route configuration and obtain it from the props. Match. params parameter
<Route path="/user/:id" />
Copy the code
- The second is in
Link
Component parametersto
It can bestring
orobject{pathname, search, hash, state}
To obtain the parameter, props. Location
<Link to={string || object}></Link>
Copy the code
- The third way is through
history.push
API, the push parameter has two forms as follows: get the parameter from props. Location
history.push(string, [state]) // state is an object parameter
history.push({pathname, search, state}) // state is an object parameter
Copy the code
API source code implementation
Router
Common low-level interface for all Router components. Typically, one of the following higher-level routers is used:
- BrowserRouter
- HashRouter
- MemoryRouter
- NativeRouter
- StaticRouter
import React, { Component } from "react";
import RouterContext from "./RouterContext";
class Router extends Component {
static computeRootMatch(pathname) {
return { path: "/".url: "/".params: {}, isExact: pathname === "/" };
}
constructor(props) {
super(props);
this.state = {
location: props.history.location
};
// Listen for location changes
this.unlisten = props.history.listen(location= > {
this.setState({ location });
});
}
componentWillUnmount() {
// Cancel the listener
if (this.unlisten) {
this.unlisten(); }}render() {
const { history, children } = this.props;
return (
<RouterContext.Provider
value={{
history.location: this.state.location.match: Router.computeRootMatch(this.state.location.pathname)}} >
{children}
</RouterContext.Provider>); }}export default Router;
Copy the code
BrowserRouter
uses the HISTORY API provided by HTML5 (pushState,replaceState, and popState events) to keep the UI and URL in sync
HashRouter
uses the hash part of the URL (window.location.hash) to keep the UI and URL in sync
MemoryRouter
Keep the history of the URL in the memory
(do not read, do not write to the address bar). Useful in testing and non-browser environments, such as React Native
Implement BrowserRouter
BrowserRouter
The history management object initializes and passes down, and location changes listen
import { createBrowserHistory } from "history";
import { Component } from "react";
import Router from "./Router";
class BrowserRouter extends Component {
constructor(props) {
super(props);
this.history = createBrowserHistory();
}
render() {
return <Router children={this.props.children} history={this.history} />; }}export default BrowserRouter;
Copy the code
Route
is the most important component of the React Router. Its basic responsibility is to render some UI when its path property matches a location
There are three ways to render using
:
- component
- render: func
- children: func
Different ways are used in different cases, and only one of them should be used in the specified
Routing configuration, match detection, content rendering
Match: children> Component >render>null; child: function; render: node
Do not match children or null(render function only)
import React, { Component } from "react";
import matchPath from "./matchPath";
import RouterContext from "./RouterContext";
class Route extends Component {
render() {
return (
<RouterContext.Consumer>{context => { const { location } = context; const { children, component, render, path, computedMatch } = this.props; const match = computedMatch ? computedMatch : path ? matchPath(location.pathname, this.props) : context.match; // location.pathname === path const props = { ... context, match }; // match children, component, render, null // do not match children(function) // return match? React.createElement(component):null return (<RouterContext.Provider value={props}>
{match
? children
? typeof children === "function"
? children(props)
: children
: component
? React.createElement(component, props)
: render
? render(props)
: null
: typeof children === "function"
? children(props)
: null}
</RouterContext.Provider>
);
}}
</RouterContext.Consumer>); }}export default Route;
Copy the code
Link
Jump links, handle click events
Parameters: : string | object
A string or object in the form of links, through the pathname, search, hash, such as the state to create the replace: bool when set to true, after click on the link will replace the current entry in the history stack, rather than adding a new entry. The default is false
Other attributes such as title, ID,className, etc
import { useContext } from "react";
import RouterContext from "./RouterContext";
function Link({ children, to, ... restProps }) {
const { history } = useContext(RouterContext);
const handleClick = e= > {
e.preventDefault(); // Block the default click behavior
// command jump
history.push(to);
};
return (
<a href={to} {. restProps} onClick={handleClick}>
{children}
</a>
);
}
export default Link;
Copy the code
Switch
The first
or
child to render to match the path
will render only one route
import React, { Component } from "react";
import matchPath from "./matchPath";
import RouterContext from "./RouterContext";
class Switch extends Component {
render() {
return (
<RouterContext.Consumer>{context => { const { location } = context; let match; // Tag matches let element; // children React.children. ForEach (this.props. Children, child => { if (match == null && React.isValidElement(child)) { element = child; match = child.props.path ? matchPath(location.pathname, child.props) : context.match; }}); return match ? React.cloneElement(element, { computedMatch: match }) : null; }}</RouterContext.Consumer>); }}export default Switch;
Copy the code
Hooks to realize
Implement useHistory, useLocation, useRouteMatch, useParams, and so on
import { useContext } from "react";
import RouterContext from "./RouterContext";
// Custom hooks
export function useHistory() {
return useContext(RouterContext).history;
}
export function useLocation() {
return useContext(RouterContext).location;
}
export function useRouteMatch() {
return useContext(RouterContext).match;
}
export function useParams() {
const match = useContext(RouterContext).match;
return match ? match.params : {};
}
Copy the code