react-router-dom

Single-page application (SPA), front-end routing changes will not refresh the page, and will not send requests to the server

Routing is divided into front-end routing and back-end routing. Both front-end and back-end routing are a key-value pair.

Front-end (path, component), one route corresponds to one component

Backend (path, function), a route corresponds to a processing function

The core of single-page application is history, that is, history under BOM. There are two modes, one is history mode, and the other is hash mode

Front-end routing changes can be monitored, so you can write the corresponding component

Preliminary writing

app

import React, { Component } from 'react'
import { Route, Link, NavLink } from 'react-router-dom'
import Hello from './components/Hello'
import World from './components/World'
import './index.css'

export default class App extends Component {

  render () {
    return (
      <div>
        // Link and Route need to be included in Router, there are two types of Router, one is BrowserRouter, the other is HashRouter
        // Corresponding to the history and hash modes respectively, it can be wrapped here, or it can be wrapped when mounted in index.js

        /* link Needless to say
        Using link will not automatically add the class name to the corresponding route
        <Link className="a" to="/Hello">Hello</Link><br />
        <Link className="a" to="/World">World</Link>
        */

        // NavLink can be used, and the active class will be added by default to the corresponding route, and the style corresponding to this class can be defined to distinguish
        // You can also customize what class name to add according to the route, using activeClassName="" to define
        <NavLink activeClassName="b" className="a" to="/Hello">Hello</NavLink><br />
        <NavLink activeClassName="b" className="a" to="/World">World</NavLink>
        // This is not a view or something, but a route with a corresponding (path, component)
        <Route path="/Hello" component={Hello}></Route>
        <Route path="/World" component={World}></Route>
      </div>
    )
  }
}

Wrap the router shell in index.js
// The entry file is to import + mount the App instance
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
// history mode
// import { BrowserRouter } from 'react-router-dom'
// hash mode
import { HashRouter } from 'react-router-dom'

// ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'))
// Hsah mode can also be used
ReactDOM.render(<HashRouter><App /></HashRouter>, document.getElementById('root'))


The routing component can receive data, encapsulate NavLink, and the label body is also an attribute (children), and it can be displayed as the label body by directly writing children

If there are multiple identical routes that will match, they need to be wrapped in a Switch block, so that when one is matched, it will stop and not continue to match

(The default is to continue to match downwards)

<Switch>
  <Route path="/about" component={About}/>
  <Route path="/home" component={Home}/>
  <Route path="/home" component={Test}/>
</Switch>

In history mode, multi-level routing refresh style is lost
localhost: the path represented by 3000 === public and public as the root path, if not found, it will return index.html, and only access public (localhost: 3000) will return index.html

Reason: The ./ request will be routed at the lowest level, and the previous level will also be regarded as the request path

Solution 1, remove . from ./, go directly to / to find the root path

Solution 2, use %PUBLIC_URL% when importing

Solution 3, use hash

Route matching method
The to in the link will match the route in the route

/home and /home/a/b cannot match (link ==> route exact match, can not give wrong, can not give less)

/home/a/b and /home match (link ==> route fuzzy match, can give more, can not give wrong, first as below)

The default is fuzzy matching, which is compared in order. If it does not match at the beginning, it will not match after that, such as /a/home/b does not match

When registering a route, **exact = {true}** enables exact matching, or just direct exact, generally not enabled

Redirect
It is slightly different from vue. This is used to cover the bottom line. It means that when there is no match, go to a certain route

<div>
    <MyLink className="a" to="/Hello">Hello</MyLink><br />
    <MyLink className="a" to="/World">World</MyLink>
    <Route path="/Hello" component={Hello} />
    <Route path="/World" component={World} />
    {/* When no route can be matched, you can use this cover, which uses to instead of path */}
    <Redirect to="/Hello" />
  </div>
---------------
Copyright statement: This article is an original article of CSDN blogger "Front Siege fff", and follows the CC 4.0 BY-SA copyright agreement. For reprinting, please attach the original source link and this statement.
Original link: https://blog.csdn.net/qq_50646256/article/details/119583442

Routing parameters

params

The parameter route passed in the link needs to be received during registration

When registering a route, it can only be received after the colon declaration, and the value is in the parms in the match in the route component props

<MyLink to={`/home/message/${message[0].id}/${message[0].tittle}`}>message001</MyLink>
<MyLink to={`/home/message/${message[1].id}/${message[1].tittle}`}>message002</MyLink>
<MyLink to={`/home/message/${message[2].id}/${message[2].tittle}`}>message003</MyLink>
{/* Since the value is passed above, it needs to be received when the route is matched here */}
<Route path="/home/message/:id/:tittle" component={Detil} />

Get the value in the Detil routing component

render () {
    const { id, title } = this.props.match.params
    console. log(this. props)
    return (
      <div>
        <h3>This is {id}</h3>
        <h3>{tittle}</h3>
      </div>
    )
  }

search parameter

You can also use the ? method to search for parameters (query parameters)

Pass parameters

<MyLink to={`/home/message/?id=${message[0].id} & amp;tittle=${message[0].tittle}`}>message001</MyLink>

There is no need to declare when receiving (it has been declared when passing)

The passed value is in props.location.search in the component object, but this is in the form of urlencode encoding

Requires the querystring library (no installation required)

import qs from 'querystring'
qs.stringify(object) // convert an object into urlencode format
qs.parse(Str) // Convert a urlencode format string into an object

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-GGt2ixpw-1628613664309)(https://secure.wostatic.cn/static/3XWnXbRZxmMUvK81PE7wBV/image.png)]

state parameter

When declaring a route, it can be an object. The route key in is pathname. This can be used to pass the state object

state parameter
When declaring a route, it can be an object, and the route key inside is pathname, which can be used to pass a state object

Registering routes also does not require a statement to receive

The passed value is in the props.location.state in the component object, not displayed on the url, even if it is refreshed, it still exists, because the histroy object is maintaining the location, although the location is an attribute of props, it is also an attribute of histroy

Note that if the cache is cleared, it will be lost, so it can be written as xxx = props.location.state || {} when receiving

Routing nesting
root routing component

<div>
  <MyLink className="a" to="/About">About</MyLink><br />
  <MyLink className="a" to="/Home">Home</MyLink>
  <Route path="/About" component={About} />
  {/* Exact match mode cannot be turned on casually. When there are sub-routes and sub-routes are redirected, the sub-routes will not be matched
  Because after clicking home here, the matching mode at this time is home/message (because of the redirection of the sub-routes under the home route)
  But at this time the route in the home component has not been registered, it can only be matched here, and only home can be matched here, but because of the exact match
  home will not be matched */}
  <Route path="/Home" component={Home} />
  {/* When no route is matched, this can be used */}
  <Redirect to="/About" />
</div>

First-level sub-routing component

 render () {
    return (
      <div>
        <h3>I am the content of Home</h3>
        <div>
          <ul className="nav nav-tabs">
            <li>
              <MyLink to="/home/news">news</MyLink>
            </li>
            <li>
              <MyLink to="/home/message">message</MyLink>
            </li>
          </ul>
          {/* register route */}
          {/* The nested route needs to be fully written, and the upper level route should also be included */}
          <Route path="/home/message" component={Message} />
          <Route path="/home/news" component={News} />
          <Redirect to="/home/message" />
        </div>
      </div>
    )

Programmatic routing navigation

The push and replace methods under history have two parameters, one path and one state parameter

The two methods are consistent in use, but the way of pushing the stack is different, here is only one

// Routing changes after clicking
<button onClick={() => { this.toThree(message[2].id, message[2].tittle) }}>Message 3</button>

// defined function
  toThree = (id, title) => {
    // pass the search parameter
    // this.props.history.push(`/home/message/?id=${id}$tittle=${tittle}`)
    // pass the params parameter, you need to declare the reception
    // this.props.history.push(`/home/message/${id}/${tittle}`)
    // Pass the state parameter, the second parameter is used to pass the state
    // this. props. history. push('/home/message', { id, title })
  }

withRouter, the general component uses the routing component method to expose withRouter(Header)

import React, { Component } from 'react'
// General components cannot use the method of the history object, that is, they cannot operate on the route
// To use it, you need to use withRouter under react-router-dom, and expose this component as a processed one
import { withRouter } from 'react-router-dom'

// You can't expose components like this, you need to expose a component processed by withRouter to operate routing
// export default class index extends Component {
// goback = () => {
// this.props.history.goBack()
// }
// render () {
// return (
// <div>
// <button onClick={this.goback}>back</button>
// </div>
// )
// }
// }
class Header extends Component {
  goback = () => {
    this.props.history.goBack()
  }
  render () {
    return (
      <div>
        <button onClick={this.goback}>Back</button>
      </div>
    )
  }
}
export default withRouter(Header)

Route Summary
Vue has a separate routing configuration file, and react has not yet learned about it. The operation of routing, whether programmatic or declarative, is defined in the component

All react history objects operate on routes

BrowserRouter is encapsulated according to the api of H5’s history (different from the history under react routing)

HashRouter uses the hash value of the url

The latter will lose data when refreshing under state parameter passing

1. The underlying principles are different:
BrowserRouter uses the history API of H5, which is not compatible with IE9 and below versions.

HashRouter uses the hash value of the URL.

2. The path expression is different
There is no # in the path of BrowserRouter, for example: localhost:3000/demo/test

The path of HashRouter contains #, for example: localhost:3000/#/demo/test

3. The impact on routing state parameters after refresh
(1).BrowserRouter has no effect, because the state is stored in the history object.

(2). After the HashRouter is refreshed, the routing state parameter will be lost! ! !

4. Note: HashRouter can be used to solve some path error related problems.