Deep understanding of react-router@4.0 use and source code parsing, reactrouter source code

Source: Internet
Author: User

Deep understanding of react-router@4.0 use and source code parsing, reactrouter source code

If you are already a react application under development, you want to introduce better routing management functions. Then, react-router is your best choice ~

The react-router version has reached 4.0.0, while the previous stable version is 2.8.1. Believe me, if your project is already using a version earlier than react-router, be sure to update it with caution, because the new version is a very big change, if you want to update, the workload is not small.

This article does not discuss version changes, just discuss the usage and source code of React-router4.0.

Source code here: https://github.com/ReactTraining/react-router

1. Prepare

You only need to introduce a package in your react appyarn add react-router-dom@next

Note: react-router-dom is a repository for react-router with minor upgrades. The Code is based on react-router.

2. Use

Here is an example:

import React from 'react'import {BrowserRouter as Router,Route,Link} from 'react-router-dom'const Basic = () => ( <Router> <div>  <ul>  <li><Link to="/">Home</Link></li>  <li><Link to="/page1">Page1</Link></li>  <li><Link to="/page2">Page2</Link></li>  </ul>  

Like the previous version, the Router component is still a container, but its role has changed. Any labels can be placed under the 4.0 Router, which means a change in the usage mode, it is more like the provider in redux. The above example shows the specific changes. The real Route is defined by Route. The Link tag does not change at present. It can still be understood as a tag. Clicking it will change the hash value of the browser Url, the Route label is used to capture the url and return the component defined in the component Attribute. You may notice that there is an exact keyword in the Route written, this keyword uniquely matches "/". Otherwise, "/" and "/xxx" will match the route with the path "/". After the exact is specified, "/page1" won't match "/" again. If you don't understand it, give it a try ~

Through the Route routing component, you can get a match parameter, which is an object that contains several data:

  1. IsExact
  2. Params: extra data contained in path
  3. Path: value of the path attribute of the Route component
  4. Url: the hash value of the actual url

Let's implement the Page2 component just now:

const Page2 = ({ match }) => ( <div> 

Easy to use. Note that only the part after the colon ":" In the Route path is equivalent to a wildcard, And the matched part of the url will be used as the match. the attributes in param are passed to the component. The attribute name is the string after the colon.

3. Router tag

Careful friends certainly noticed that in the above example, the Router I imported is BrowserRouter. What is this? If you use an earlier version of react-router, you must know history. History is used to manage historical records in different browsers or environments. When I jump to or click the back button of the browser, history must record these changes, previous react-router divides history into three types.

  1. History of the earlier version of hashHistory Browser
  2. History of browserHistory h5
  3. History in the memoryHistory node environment, which is stored in memory

In versions earlier than 4.0, react-router implements three methods for creating history in three cases: createHashHistory, createBrowserHistory, and create MemoryHistory. Here we will not discuss their different processing methods, if you are curious, you can get to know about it ~
In version 4.0, the three history types are built in react-router-dom, so we can see BrowserRouter, HashRouter, and MemoryRouter. Of course, you can still use the router in React-Router, and then use createHistory to create history for input.

React-router's history library still uses https://github.com/ReactTraining/history

4. Route label

In the example, you may have noticed several Route prop

  1. Exact: propType. bool
  2. Path: propType. string
  3. Component: propType. func
  4. Render: propType. func

They are not required. Note that if the path is not assigned a value, the Route is rendered by default.

The role of Route is to render the component or render content in component when the url matches the value of the path attribute in Route.

Of course, Route actually has several attributes, such as location, strict, and chilren. I hope you can understand them yourself.

Speaking of this, how does the Route internal implement this mechanism? It is not hard to guess that it must be implemented using a matching method. So how does Route know that the url is updated and then re-matched and rendered?

Sort out your ideas. In a web application, there are only two ways to change the url. One is to use a hyperlink to jump, and the other is to use the browser's forward and backward functions. The former is triggered after the Link jump event is triggered. What about the latter? Route uses the history listen method we mentioned above to listen for url changes. To prevent the introduction of new libraries, Route creators chose to use the popState event in html5. This event will be triggered by clicking the browser's forward or backward button, let's take a look at the Route code:

Class Route extends Component {static propTypes: {path: PropTypes. string, exact: PropTypes. bool, component: PropTypes. func, render: PropTypes. func,} componentWillMount () {addEventListener ("popstate", this. handlePop)} componentWillUnmount () {removeEventListener ("popstate", this. handlePop)} handlePop = () => {this. forceUpdate ()} render () {const {path, exact, component, render,} = this. pro Ps // location is a global variable const match = matchPath (location. pathname, {path, exact}) return (// interestingly, here we can see the rendering priority of each attribute. What is the first component of component? (Match? React. createElement (component, props): null): render? (// Render prop is next, only called if there's a match? Render (props): null): children? (// Children come last, always called typeof children === 'function '? (Children (props )):! Array. isArray (children) | children. length? (// Preact defaults to empty children array React. Children. only (children): (null ))}}

Here I only post the key code. If you have used React, I believe you can understand it. Route adds a listener for popState events when the component is to be mounted. Whenever a popState event is triggered, use forceUpdate to force refresh based on the current location. the pathname is matched once and then rendered based on the results.

PS: In the latest code, the Route source code is actually re-rendered through setState in componentWillReceiveProps. The match attribute exists as the state of the Route component.

So how is the key matchPath method implemented?
Route introduces an external library: path-to-regexp. This pathToRegexp method is used to return a regular expression that meets the requirements. For example:

let keys = [],keys2=[]let re = pathToRegexp('/foo/:bar', keys)//re = /^\/foo\/([^\/]+?)\/?$/i keys = [{ name: 'bar', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }] let re2 = pathToRegexp('/foo/bar', keys2)//re2 = /^\/foo\/bar(?:\/(?=$))?$/i keys2 = []

For details about it you can see here: https://github.com/pillarjs/path-to-regexp

It is worth mentioning that the matching result is cached in the matchPath method. If it is a matched string, you do not need to perform pathToRegexp again.

The subsequent code is clear:

Const match = re.exe c (pathname) if (! Match) return nullconst [url,... values] = matchconst isExact = pathname = url // If exact is true, pathname = urlif (exact &&! IsExact) return nullreturn {path, url: path = '/' & url = ''? '/': Url, isExact, params: keys. reduce (memo, key, index) => {memo [key. name] = values [index] return memo },{})}

5. Link

Do you still remember the two methods mentioned above to change the url? Let's talk about the other method. Link, let's take a look at its parameters:

static propTypes = { onClick: PropTypes.func, target: PropTypes.string, replace: PropTypes.bool, to: PropTypes.oneOfType([  PropTypes.string,  PropTypes.object ]).isRequired}

OnClick is not mentioned. The target attribute is the target attribute of tag a, and to is equivalent to href.

Replace indicates whether the jump link overwrites the current url in history. If it is true, the new url overwrites the current value in history, rather than adding a new one to it.

HandleClick = (event) =>{ if (this. props. onClick) this. props. onClick (event) if (! Event. defaultPrevented & // whether the default event is blocked! This.props.tar get & // avoid opening a new window! IsModifiedEvent (event) // ignore the special key value, whether ctrl, shift, alt, meta are simultaneously pressed) {event. preventDefault () const {history} = this. context. router const {replace, to} = this. props if (replace) {history. replace (to)} else {history. push ()}}}

Note that history. push and history. replace use the pushState and replaceState methods.

6. Redirect

I want to talk about the Redirect component separately. The source code is very interesting:

Class Redirect extends React. component {//... omitting part of the code isStatic () {return this. context. router & this. context. router. staticContext} componentWillMount () {if (this. isStatic () this. perform ()} componentDidMount () {if (! This. isStatic () this. perform ()} perform () {const {history} = this. context. router const {push, to} = this. props if (push) {history. push (to)} else {history. replace (to)} render () {return null }}

It is easy to notice that this component does not have a UI, And the render method returns a null. It is easy to have such a question. Since there is no UI, why does the creator of react-router still choose to write Redirect as a component?

I think we can look at the reason from the author's "Just Components API.

I hope this article will help you better create your React application.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.