preface

The first project of front-end work was to cooperate with colleagues to build a large SPA — enterprise back-end management platform, whose application architecture was similar to enterprise wechat · management platform. React stack is used to complete front-end development, and The React Router becomes an essential tool. The non-refresh component switch makes the user experience better. After reading a lot of learning documents and practicing in work, this article summarizes the React-Router.

Problem solved

Routing makes it easy to add, switch components, and keep pages and urls in sync, which is widely used in SPA. With react-Router, we don’t need to manually find the components that need to be rendered, and we don’t need to write complex logic. We just need to complete the corresponding route configuration, and leave the rest to the routing agent.

Use cases

import React from 'react'
import { render } from 'react-dom'

// First we need to import some components...
import { Router, Route, Link } from 'react-router'

const App = React.createClass({
  render() {
    return(< div > < h1 > App < / h1 > {/ * < a > into the < Link > * /} < ul > < li > < Link to = "/ about" > about < / Link > < / li > < li > < Link To ="/ Inbox ">Inbox</Link></li> </ul> {/* Then replace '<Child>' router with 'this.props. Children' to help us find this Child The component to which childern corresponds is visible in the nested relation of the routing rule: in this case, About or Inbox or undefined */} {this.props. Children} </div>)}}) // Finally, We render the <Router> with some <Route>. // Router is a routing container. Route is a real route. The routes can be nested. // These are the things that routing provides. React.render(( <Router> <Route path="/" component={App}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox} /> <Route path="messages/:id" component={Message} /> </Route> </Router> ), document.body)Copy the code

The Router is a React component used as a routing container. The Route contains routing rules. In use we can use the page hierarchy to build routing rules. There are two important attributes in a Route:

  • The matching rule for the route with the path attribute at the top is displayed in the browser address bar after the domain name. When the path attribute is omitted, the specified component of the routing node is always loaded.
  • The Component property specifies the component to mount when the URL matches this routing rule.

With the above configuration, the application renders the URL as follows:

URL component
/ App
/about App -> About
/inbox App -> Inbox
/messages/[someid] App -> Message

Path to the grammar

A routing path is a string pattern that matches a URL (or part of it). Did you notice something different about rule 3 of routing? It has path=”messages/: ID “and does not specify an exact routing address.

There are several special matching rules in the React-Router:

  • :paramNameMatches a segment located/,?or#The URL after that.
  • (a)The rules inside them are optional and can be ignored when matching.
  • *Matches any character (not greedy) until the next character or the end of the entire URL.
  <Route path="/hello/:name">         // Matches /hello/ Michael and /hello/ Ryan
  <Route path="/hello(/:name)">       // Matches /hello, /hello/ Michael and /hello/ Ryan
  <Route path="/files/*.*">           // Match /files/hello.jpg and /files/path/to/hello.jpg
Copy the code

We can use relative addresses like the use case, or we can use absolute addresses like the following, which is useful when routing rules are deeply nested and can simplify our routing rules.

React.render(( <Router> <Route path="/" component={App}> <IndexRoute component={Index} /> <Route path="about" Component ={About} /> <Route path=" Inbox "Component ={Inbox}> {/* Replace messages/:id */} <Route with /messages/:id path="/messages/:id" component={Message} /> </Route> </Route> </Router> ), document.body)Copy the code

With the above configuration, the application renders the URL as follows:

URL component
/ App -> Index
/about App -> About
/inbox App -> Inbox
/messages/[someid] App -> Inbox -> Message

Note: Absolute paths cannot be used in dynamic routing.

History

React-router is built on history. History knows how to listen for changes in the browser’s address bar, parse this URL into a Location object, and then the Router uses it to match the route and render the corresponding component correctly.

There are three common forms of history:

  • browserHistory
  • hashHistory
  • createMemoryHistory

To do this, pass history into:

// JavaScript module import
import { browserHistory } from 'react-router'

render(
  <Router history={browserHistory} />,
  document.getElementById('app')
)
Copy the code

React to the Router is recommended to use BrosbrowserHistoryerHistory, it USES the browser History apis to handle the URL. The server needs to cooperate and be prepared to handle urls. HashHistory uses the hash (#) part of URK to create a route of the form example.com/#/some/path. CreateMemoryHistory is used for SSR (server-side rendering) and is not covered here.

IndexRoute and Redirect

IndexRoute

When the link we visit is www.demo.html/, the page will load the App component. At this point, this.props. Children in the render of App is undefined because our route does not match the child components of App. At this point, we can use IndexRoute to set up a default page. The modified routes are as follows:

React.render(( <Router> <Route path="/" component={App}> <IndexRoute component={Index}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox} /> <Route path="messages/:id" component={Message} /> </Route>  </Router> ), document.body)Copy the code

At this point, this.props. Children in App render will be the component.

Redirect

Consider the question of what happens if you enter a URL in the address bar that does not match the routing rules, such as www.demo.html/#/noroute. The page would be blank and empty. We have a requirement that when we visit www.demo.html/#/inbox, I want to redirect the address to www.demo.html/#/about, render the About component, or fix the blank error above to redirect to the About component. To solve this problem, you can use the Redirect for redirection.

React.render(( <Router> <Route path="/" component={App}> <IndexRoute component={Index}> <Route path="about" Component ={About} /> <Route path=" Inbox "Component ={Inbox} /> <Route path="messages/: ID" Component ={Message} /> {/* Jump /inbox to /about */} < inbox from="inbox" to="about" /> </Route> </Router>), document.bodyCopy the code

Routing hop

Route forwards can be divided into internal forwards and external forwards. The internal forwards are completed by Link, just like the principle of A tag. Component hops can be done using the push method.

Link

The Link component is used to replace the A tag and generate a Link that allows the user to click and jump to another route, as in the use case. The activeStyle attribute adds styles to the current route. Or use activeClassName to add a class to the current route.

<Link to="/about" activeStyle={{color: 'red'}}>About</Link>
<Link to="/inbox" activeStyle={{color: 'green'}}>Inbox</Link>
Copy the code

push

We need to jump when we submit the form and click the button, so we can use the push method to do this.

// somewhere like a redux/flux action file:
import { browserHistory } from 'react-router'
browserHistory.push('/some/path')
Copy the code

IndexLink

If you use Home in this app, it will always be active, activeStyle and activeClassName will be disabled, or always active. All routing rules start with a slash. This is a real problem because we only want Home to be activated and linked to after it has been rendered.

Home
if you need a link to/activated after the Home route has been rendered, that is, for exact matching, / only matches the root route, use

Home
.

Or use the onlyActiveOnIndex attribute of the Link component to achieve the same effect.

<Link to="/" activeClassName="active" onlyActiveOnIndex={true}>
  Home
</Link>
Copy the code

Dynamic routing

The React-Router (Versoin 4) implements dynamic routing.

One of the first problems with large applications is the size of the JavaScript required to load. Your program should load only the JavaScript needed for the current rendering page. Some developers refer to this approach as “code splicing” — splitting all the code into small packages that can be loaded on demand while the user is browsing. Route matching and component loading in The React-Router are done asynchronously, allowing you to lazily load not only components, but also route configurations. Route can define getChildRoutes, getIndexRoute, and getComponents. They all execute asynchronously and are called only when needed. We call this “gradual matching.” The React-router gradually matches the URL and loads only the path configuration and components required for the page corresponding to the URL.

const CourseRoute = {
  path: 'course/:courseId',

  getChildRoutes(location, callback) {
    require.ensure([], function (require) {
      callback(null[require('./routes/Announcements'),
        require('./routes/Assignments'),
        require('./routes/Grades'),
      ])
    })
  },

  getIndexRoute(location, callback) {
    require.ensure([], function (require) {
      callback(null.require('./components/Index'))
    })
  },

  getComponents(location, callback) {
    require.ensure([], function (require) {
      callback(null.require('./components/Course'))}}}Copy the code

Hook Life cycle Hook

Route can define two hooks onEnter and onLeave to capture the time of entering and leaving a Route and perform some operations, such as completing permission verification.

In the process of route jump, onLeave hook will be triggered in all departing routes, from the lowest child route to the end of the outermost parent route. The onEnter hook then starts at the outermost parent route and ends at the lowermost child route. The same mechanism for event capture and event bubbling.

<Router>
    <Route path="about" component={About} onEnter={/*dosomething*/} />
    <Route path="inbox" component={Inbox}>
      <Redirect from="messages/:id" to="/messages/:id" onLeave={/*dosomething*/} />
    </Route>
  </Router>
Copy the code

In the code above, if the user leaves /messages/:id and enters /about, the following hooks are triggered in sequence.

/messages/:id onLeave/Inbox onLeave /about onEnterCopy the code

RouterWillLeave is the lifecycle hook when leaving the current route. This method prevents route switching if it returns false, otherwise it returns a string prompting the user to confirm before leaving the route.

import { Lifecycle } from 'react-router'

const Home = React.createClass({

  // Assuming Home is a route component, it might use
  Lifecycle Mixin will get a routerWillLeave method.
  mixins: [ Lifecycle ],

  routerWillLeave(nextLocation) {
    if (!this.state.isSaved)
      return 'Your work is not saved! Are you sure you want to leave? '
  },

  // ...

})
Copy the code

Corner

  • The routing algorithm matches routes from top to bottom based on the defined sequence, and matches the first route that matches the rule.
  • Can be achieved bythis.props.params.idIn order to get/:idThe id.
  • URL query string /foo? Bar =baz, that worksthis.props.location.query.barTo obtain.