Take a look at the react-Router example
const BasicExample = () => (
<Router>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
Copy the code
Click here to see the above code in action
The purpose of this article is to show how the React-Router renders different components based on the URL in the browser. For details on how urls change, see the next article on React-Router: Link hops.
The base depends on path-to-regexp
React to the router provides specialized routing matching method matchPath (located in the router/modules/packages/react matchPath. Js), rely on behind this method is the path – to – the regexp package.
The path-to-regexp input is a path string (that is, the value of path defined in Route), and the output contains two parts
- Regular expressions (RE)
- An array of keys (used to record param keys)
Path-to-regexp is defined as a capture group for the parameter in PATH (bar in the following example), and the name of the parameter (bar) is recorded in the array keys
var pathToRegexp = require('path-to-regexp')
var keys = []
var re = pathToRegexp('/foo/:bar', keys) console.log(re); console.log(keys); / / output / ^ \ / foo \ / (/ [^ \] +? (? : \ /)? $/i [ { name:'bar',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
partial: false,
pattern: '[^ \ \ /] +? '}]Copy the code
MatchPath core
The matchPath method first obtains the regex corresponding to the path defined on the Route through path-to-regexp method, and then performs regular matching between the generated regular expression and pathname in THE URL to determine whether it is matched.
console.log(re.exec('/foo/randal'));
console.log(re.exec('/foos/randal')); / / output ['/foo/randal'.'randal', index: 0, input: '/foo/randal' ]
null
Copy the code
Param keys can be associated with param keys by traversing the result of the match and the keys array, as shown below:
const match = re.exec('/foo/randal');
const [url, ...values] = match;
const params = keys.reduce((memo, key, index) => {
memo[key.name] = values[index];
return memo;
}, {})
console.log(params) // {"bar": "randal"}
Copy the code
Finally, matchPath returns NULL for an unmatched match and an Object for a successful match
return {
path, // /foo/:bar
url: // /foo/randal
isExact, // false
params: // {"bar": "randal"}};Copy the code
The Route of rendering
The Route component maintains a state(match) whose value is taken from the execution result of matchPath, as shown below
state = {
match: this.computeMatch(this.props, this.context.router)
};
computeMatch({ computedMatch, location, path, strict, exact, sensitive }, router) {
if (computedMatch) returncomputedMatch; // computedMatch is left to the Switch using const {route} = router; const pathname = (location || route.location).pathname;return matchPath(pathname, { path, strict, exact, sensitive }, route.match);
}
Copy the code
Route creates the associated Component only when state.match is not null.
The Route association component has multiple forms (render, Component, children). The difference between children and render and Component is that children are executed regardless of match, even if match is null. The children function is also executed, and the reason for the children design will be discussed in an upcoming article on the Link component.
render() { const { match } = this.state; const { children, component, render } = this.props; const props = { match, ... };if (component) return match ? React.createElement(component, props) : null;
if (render) return match ? render(props) : null;
if (typeof children === "function") return children(props);
return null;
}
Copy the code
The react-router component renders different routes based on the URL, but sometimes using Route alone can cause problems. For example:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
Copy the code
If the current url is /about, this will render the About, User, and NoMatch components on the page, but we want to render only the About component.
Switch Path match before
For the above problem, you can wrap the Switch component around it
<Switch>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
Copy the code
After the Switch wrap, only the about component will be rendered for /about, and only the User component for /about.
The feature of the Switch component is that only one Route will be selected from the children to render. In order to achieve the purpose of rendering only one Route, the Switch adopts the Route path matching preposition and does not rely on the Render method of Route to render components, but starts the Route path matching in the Switch. Once a matching path is found, it is selected for rendering. The key code for the Switch is as follows
render() {
const { route } = this.context.router;
const { children } = this.props;
const location = this.props.location || route.location;
letmatch, child; Children. ForEach (children, element => {// Children => {// Children => {// Children => {if(match == null && React.isValidElement(element)) { const { path: pathProp, exact, strict, sensitive, from } = element.props; const path = pathProp || from; child = element; match = matchPath( location.pathname, { path, exact, strict, sensitive }, route.match ); }});return match
? React.cloneElement(child, { location, computedMatch: match })
: null;
}
Copy the code
The above code passes match, the result of matchPath execution, into the Route with computedMatch as the key. In this way, duplicate matching is avoided and the computeMatch method of Route can be reused directly. See the Route Rendering section earlier for the computeMatch code.
Enter the next section on react-Router Link jumping