React 0 basic learning route - Graphic in-depth description of react route and its detailed cases (with detailed case code analysis process attached)

1. key refining

React routing

  • React-Router
    • Native
    • Web : react-router-dom
  • BrowserRouter / HashRouter: a routing root component that provides basic routing services
  • Route: a route component, which handles the mapping (binding) between URLs and components
  • Link: dynamically generate a tag and provide navigation service

2. react JS - route react router DOM

2.1 routing

In fact, this route is the same as the router we usually use. It is not much different. Its purpose is content distribution (shunting). In fact, it is to cut a whole block of content into parts and access them in blocks according to certain rules. For example, now there are many computers. If you want to manage them together, you need to buy a router. Its core function is to process the requests and data we send every time. It is equivalent to that we now have a huge resource, so how to manage the resource? It is impossible to cram such huge resources into the receiver every time a request is made. Both the sender and the requester will be exhausted. Generally, resources are classified according to different categories and requirements, and they are organized and divided. At this time, it is necessary to obtain data in some way.

Generally, url is used to obtain data. It corresponds to the corresponding services and resources at the back end, that is, different data at the back end can be obtained through different URLs. In fact, it is used for content distribution, so the actual front-end routing concept is very similar.

When the application becomes complex, it needs to be processed and displayed in blocks. In the traditional mode, we divide the entire application into multiple pages, and then connect through the URL. However, there are some problems with this method. Every time you switch pages, you need to resend all requests and render the entire page. This will not only affect the performance, waste resources, but also cause the entire JavaScript to re execute and lose its state.

For example, both a and b pages are the same, and 99% of them are the same, so there are some different words. If you switch from page a to page b, it is also equivalent to sending a new request to request the resources of page b, and the browser will re render the entire page, which is a great waste of resources.

To solve this problem, use js to pull the data, not a whole page, but a changing part. If the first request is a home page, the browser requests the entire page. But the second time, for example, when you jump to the details page, it is not necessary to request a complete page. At this time, we send the request to the back end through ajax. The data transmitted by the back end is only the data of different parts of the page, not the whole new page. After the current page gets this data, it will dynamically replace the parts of the page that need to change through a series of DOM operations, and keep the unchanged parts. Such an operation is not actually a request sent by the browser itself, so the resulting content will not be re rendered by the browser. It will use js to perform local updates by operating dom. In this way, you can save a lot of performance without changing the state of the page.

If there is a complicated page, there is a form in the page. When filling in the form regularly, there is a news on the side. In the process of writing, if you want to watch the news, you need to update the news. Once you click it, you will only replace the part of the news through js. Our form will not move. At this time, it does not render the entire page. It can better preserve the user's operation state in the page, that is, the user experience is very good. We usually call this mode SPA (single page application).

2.1.1 SPA

Single Page Application: Single Page Application. The whole application only loads one page (entry page). In the subsequent interaction with users, the structure and content are dynamically generated on this single page through DOM operation

Advantages:

  • Better user experience (less waiting and blank caused by request, rendering and page Jump), faster page switching (no re rendering of the whole page)
  • Re front end, data and page content are completed by asynchronous request (AJAX) + DOM operation, and the front end handles more business logic

Disadvantages: (there will be many technologies to solve these problems)

  • The first screen processing is slow (because a lot of data and logic are put in the front end, the page response speed will be slower)

  • Not conducive to SEO (search engine optimization)

2.1.2 page switching mechanism of Spa

There are two main ways to switch pages in SPA.

Although SPA is a single page, if it is all done through Ajax and dom rendering, for example, if we now request a home page and use ajax to request content, there will be a problem. If you want to see the list alone at this time, don't you want to see so much content on the home page? At this time, you will find that our operation cannot be skipped, that is, we must follow a certain way: Step 1, step 2,..., and click until you see the list. It cannot be presented to you as a separate way, because all subsequent operations are completed through this portal. You must enter the portal first, and you can see what you want to see step by step through the portal. In this case, it will be very tedious and troublesome. At this time, I came up with a way to forge URLs to locate different operations. You don't need to click n steps to access the page after n steps are completed. However, we do not want this url to generate a real request. At this time, we adopt the following method:

The main modes of front-end routing (change the url in these two ways, but do not send a request when changing the url, and then listen to its events. Put the logic of page rendering in the callback function. When js finds that the url has changed, it will dynamically render the page content we want to see according to the url change.):

  • URL Hash based routing
  • HTML5 History API based routing

Although the contents of SPA are dynamically processed through JavaScript on one page, they still need to be displayed in different situations according to the needs. If only relying on the internal mechanism of JavaScript to judge, the logic will become too complex. By combining JavaScript with URL, JavaScript handles different logic according to the changes of URL, and only needs to change the URL in the interaction process. The way to associate different URLs with the corresponding JavaScript logic is routing, which is essentially the same as the idea of back-end routing.

2.1.3 back end routing and front end routing

The back-end route is similar to the front-end route in essence. Both of them associate and bind different URL s with an operation to get different results

2.1.3.1 back end routing

Send the request to the back-end server through HTTP. After receiving the request, the back-end server performs different operations according to different request URL s and returns the processed data (JSON, HTML, JS code, CSS, image...)

  • Need to send HTTP request
  • The business logic is processed by the back end, and the processed results are returned to the front end (browser)

2.1.3.2 front end routing

The front-end route only changes the URL or some part of the URL, but it will not directly send the request. It can be considered that it only changes the URL on the browser address bar. JavaScript handles the change of the URL through various means, and then dynamically changes the structure of the current page through DOM operation

  • HTTP requests will not be sent directly when the URL changes
  • Business logic is completed by front-end JavaScript

The main front-end routing modes at present:

  • URL Hash based routing
  • HTML5 History API based routing
2.1.3.2.1 URL Hash

Change the URL by modifying the Hash value of the URL. The change of Hash will not send a request. At the same time, JavaScript dynamically handles logic and page rendering by listening to hashchange events

advantage

Good compatibility

shortcoming

Unsightly URL and unfriendly SEO

2.1.3.2.2 HTML5 History API

Encapsulate a function that dynamically changes the URL through the API provided by HTML5 History. In this way, no request will be sent, and then the logic and page rendering will be processed according to the target URL to be changed

The URL Hash pattern is similar to the data interception mechanism in Vue

The HTML5 History API pattern is similar to react setState in JS

2.1.4 react Routing in JS

React The basic idea of JS routing is to compare different URLs with some specified react JS components, different URL rendering shows different components, and other frameworks (such as vue and angular) have the same idea

2.2 React Router

After understanding the basic routing mechanism, we don't need to build wheels repeatedly. We can directly use the React Router Library

https://reacttraining.com/react-router/

The React Router provides a variety of routing libraries in different environments

  • web
  • native

2.2.1 React Router based on Web

The web-based React Router is: React Router DOM

2.2.1.1 installation

npm i -S react-router-dom

2.2.1.2 overview

The core of react router DOM is components. It provides a series of components, such as:

  • Router components
  • BrowserRouter component
  • HashRouter component
  • Route component
  • Link as
  • NavLink assembly
  • Switch component
  • Redirect component

And other API s to complete the routing function

2.3 Foundation

2.3.1 application scenario (I)

Suppose there are two pages in the current application, and the relationship between the corresponding URL and the page

/                :    home page
/about    :    About us

As soon as the user enters the home page, click the link or button inside to jump to the "about us" page.

Now instead of writing two html pages and sending two requests in the traditional way, React is used to build. After React rendering, a page will be formed. The content seen in this page is actually the main component, which is actually converting pages into components. Then, in the form of url, it is based on the api of htmlhistory, or through the two modes of url hash. When the url changes, it shows users different components. In fact, a part of the page will change according to different URLs to display different component contents. This is actually the concept of front-end routing.

2.3.1.1 Router components

Page = component
Routing: according to the changes of different URLs, different components are rendered at the specified location in our application to display different contents

Component division types (note that they are not independent of each other, but may be related to each other. Here, only functional division is made):

  • Page component (view component). A page component generally corresponds to a complete page (complete: the page represented by a url) (such as landing page and registration page)
  • Functional components (components that have certain functions but are not a complete page in general, such as rotation chart, dialog box, etc., and functional components are part of the surface components)
    • Functional components with views (carousel map)
    • Function components without views, i.e. business type function components (data filtering, data request - as a container, error capture (send errors to the specified mailbox))
  • Container assembly

The whole structure of the project also needs to be classified:

Components (functional components, container components)

views (view component)

2.3.1.1.1 exmaple01

Application scenario (I)

2.3.1.1.1.1 exmaple01-1

Frame implementation.

app.js

import React from 'react';
 
import Home from './views/Home';
import About from './views/About';
 
class App extends React.Component {
 
    constructor(props) {
        super(props);
    }
 
    render() {
        return (
            <div className="App">
                <Home/>
                <About/>
            </div>
        )
    }
 
}
 
export default App;

src/views/Home.js

import React from 'react';
 
export default class Home extends React.Component {
 
    render() {
        return (
            <div>
                <h2>Product list</h2>
            </div>
        );
    }
 
}

src/views/About.js

import React from 'react';
 
export default class About extends React.Component {
 
    render() {
        return(
            <div>
                About us
            </div>
        );
    }
 
}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.01-1
Branch: branch4

commit description:v3.01-1-example01-1 (application scenario (I) - frame Implementation)

tag: v3.01-1

2.3.1.1.1.2 example01-2
console.log(window.location);

hash is actually the content \

Set default homepage and url through hash

app.js

 
 
import React from 'react';
 
 
import Home from './views/Home';
import About from './views/About';
 
 
class App extends React.Component {
 
    constructor(props) {
        super(props);
    }
 
    render() {
        // console.log(window.location);
 
        let hash = window.location.hash || '#home';
 
        console.log(hash);
 
        return (
            <div className="App">
                <Home/>
                <About/>
            </div>
        )
    }
 
}
 
export default App;

 
 
import React from 'react';
 
 
import Home from './views/Home';
import About from './views/About';
 
 
class App extends React.Component {
 
    constructor(props) {
        super(props);
    }
 
    render() {
        // console.log(window.location);
 
        let hash = window.location.hash || '#home';
 
        console.log(hash);
 
        return (
            <div className="App">
                {/*<Home/>*/}
                {/*<About/>*/}
 
                {
                    hash === '#home' && <Home />
                }
 
                {
                    hash === '#about' && <About />
                }
            </div>
        )
    }
 
}
 
export default App;

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.01-2
Branch: branch4

commit description:v3.01-2-example01-2 (application scenario (I) - set the default homepage and url through hash)

tag: v3.01-2

The principle here is not difficult, but if users click, jump to the page. You need to monitor the changes of hashchange. Considering the rules of url after hash, the whole page will be more complex, and the actual requirements are complex. In fact, these principles are used internally in the react router. Only after it is encapsulated, it provides a better way to use it. Many components are encapsulated internally.

If we want a part of the page to be dynamically displayed according to the URL, we need to use the Router component, which is a container component. We only need to wrap the root component corresponding to the URL with it

The react router DOM provides us with several router sub components (functional components and container components) based on different patterns

  • BrowserRouter component
  • HashRouter component
  • Memoryroouter component
  • Nativeroouter component
  • StaticRouter component
2.3.1.1.2 BrowserRouter component

Routing component based on HTML5 History API

2.3.1.1.3 HashRouter components

URL Hash based routing component

css

ul {
    margin: 0;
    padding: 0;
}
 
li {
    list-style: none;
}
 
.item-list li {
    padding: 10px;
    display: flex;
    justify-content: space-between;
    height: 30px;
    line-height: 30px;
    border-bottom: 1px dotted #333;
}
.item-list li.head {
    font-weight: bold;
}
.item-list li span {
    min-width: 200px;
}
 
.pagination {
    margin: 10px;
}
.pagination a {
    margin: 0 5px;
    display: inline-block;
    width: 30px;
    height: 30px;
    background-color: #f4f4f5;
    line-height: 30px;
    text-align: center;
    cursor: pointer;
    color: #606266;
    text-decoration: none;
}
.pagination a:hover {
    color: #409eff;
}
.pagination a.active {
    background-color: #409eff;
    color: #fff;
    cursor: text;
}
.pagination .goto {
    margin: 0 5px;
    box-sizing: border-box;
    width: 80px;
    height: 30px;
    border: 1px solid #dcdfe6;
    outline: none;
    text-align: center;
    vertical-align: top;
}

App.js

import React from 'react';
 
import {BrowserRouter as Router} from 'react-router-dom';
// import {HashRouter as Router} from 'react-router-dom';
 
import BaseApp from './BaseApp/Index';
 
function App() {
    return (
        <div>
            <h1>React-Router</h1>
            <hr/>
 
            <Router>
                <BaseApp />
            </Router>
        </div>
    );
}
 
export default App;
import {BrowserRouter as Router} from 'react-router-dom'

Import the BrowserRouter component and name the Router alias for easy use

<Router>
      <BaseApp />
</Router>

Use routing only for BaseApp components in the page

./BaseApp/Index.js

import React from 'react';
import {Route, Link} from 'react-router-dom';
 
import Home from './Home';
import About from './About';
 
export default class BaseApp extends React.Component {
 
    render() {
        return(
            <div>
                <h2>Routing infrastructure usage</h2>
 
                <nav>
                    <Link to="/">Home</Link>
                    <span> | </span>
                    <Link to="/about">About</Link>
                </nav>
                <br/>
 
                <Route exact path='/' component={Home} />
                <Route path='/about' component={About} />
            </div>
        );
    }
 
}
import {Route} from 'react-router-dom';

2.3.1.2 Route component

Note that this component does not have the letter r. it is used to set and apply a single Route information. The region where the Route component is located is the region that the subsequent component will display when the URL matches the path attribute set by the current Route

<Route path='/' component={Home} />

When the URL is: '/', the component Home will be displayed here

2.3.1.2.1 exact

The exact attribute indicates that the route uses the exact matching mode. In the non-exact mode, '/' matches all routes starting with '/'

2.3.1.3 Link components

The Link component is used to handle functions similar to the a Link (it will generate an a tag in the page), but it should be noted here that the react Route DOM intercepts the default action of the actual a tag, and then processes it according to all the used routing modes (Hash or HTML5). The URL is changed, but no request occurs. At the same time, the corresponding component is displayed in the specified location according to the settings in the Route

2.3.1.3.1 to attribute

The to attribute is similar to the href in the a tag

2.3.1.4 example02

Scenario (I) application.

2.3.1.4.1 example02-1

HashRouter component:

  • Only components contained by the HashRouter can respond to the route

  • BrowserRouter: based on HTML5 History API

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
// import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {HashRouter} from 'react-router-dom';
 
ReactDOM.render(
    <HashRouter>
        <App />
    </HashRouter>,
    document.getElementById('root')
);
 
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Route configures the mapping relationship between URLs and components: what URLs and components are located on the page. The location is the corresponding location for component rendering after meeting the requirements.

path corresponds to url and component corresponds to component

src/App.js

import React from 'react';
 
import {Route} from 'react-router-dom';
 
import Home from './views/Home';
import About from './views/About';
 
class App extends React.Component {
 
    constructor(props) {
        super(props);
    }
 
    render() {
 
        return (
            <div className="App">
                <h1>React route</h1>
                <Route path="/" component={Home}/>
            </div>
        )
    }
 
}
 
export default App;
                    <h1>React route</h1>
                    <hr/>
                    <Route path="/" component={Home}/>
                    <Route path="/about" component={About}/>

It is found that the home page is also displayed. At this time, the routing url meets both the home page and about, so we need to match it accurately.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-1
Branch: branch4

commit description:v3.02-1-example02-1 (application scenario (I) - React route matching)

tag: v3.02-1

2.3.1.4.2 example02-2

The exact attribute indicates that the route uses the exact matching mode. In the non-exact mode, '/' matches all routes starting with '/'

                    <h1>React route</h1>
                    <hr/>
                    {/*<Route path="/" component={Home}/>*/}
                    <Route path="/" component={Home} exact />
                    <Route path="/about" component={About}/>

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-2
Branch: branch4

commit description:v3.02-2-example02-2 (application scenario (I) - React route exact matching)

tag: v3.02-2

2.3.1.4.3 example02-3

It is impossible for a user to manually enter the url when performing page Jump, so the above cannot be applied. Usually, we use the UI method to associate the elements of the page for users to click and jump.

                    <h1>React route</h1>
                    <hr/>
                    <Route path="/" component={Home} exact />
                    <Route path="/about" component={About}/>
 
                    <nav>
                        <a href="/">home page</a>
                        <span> | </span>
                        <a href="/about">About us</a>
                    </nav>

This is wrong, it will only refresh the page and no response! Must bring \.

                    <h1>React route</h1>
                    <hr/>
                    <Route path="/" component={Home} exact />
                    <Route path="/about" component={About}/>                  
                    <nav>
                        <a href="#/"> Home Page</a>
                        <span> | </span>
                        <a href="#/About "> about us</a>
                    </nav>

Some people may ask, why can the corresponding components be displayed?

Because the react router DOM will listen for hash changes, we only need to trigger the hash changes. The hashchange event will be triggered inside the library.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-3
Branch: branch4

commit description:v3.02-3-example02-3 (application scenario (I) - React route exact matching, UI mode control)

tag: v3.02-3

2.3.1.4.4 example02-4

But the above form is not very good (the url is also ugly). The above is the hash mode. Next, we will demonstrate the historyApi mode.

BrowserRouter: based on HTML5 History API.

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {HashRouter, BrowserRouter} from 'react-router-dom';

ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
);
 
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

It is based on html5 and / is more beautiful.

                    <nav>
                        <a href="/">home page</a>
                        <span> | </span>
                        <a href="/about">About us</a>
                    </nav>

But we will find a problem, that is, it refreshed our entire page! After the refresh, the main file will be displayed according to the url.

If there is an input, it will be a hole!

                    <h1>React route</h1>
                    <hr/> 
                    <nav>
                        <a href="/">home page</a>
                        <span> | </span>
                        <a href="/about">About us</a>
                    </nav>
                    <input type="text"/>
                    <hr/>
                    <Route path="/" component={Home} exact />
                    <Route path="/about" component={About}/>

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-4
Branch: branch4

commit description:v3.02-4-example02-4 (application scenario (I) - loss of status caused by using the BrowserRouter component)

tag: v3.02-4

2.3.1.4.5 example02-5

How to deal with it? Don't use the native a tag! Its link component is recommended.

    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
    import Home from './views/Home';
    import About from './views/About';
 
    class App extends React.Component {
 
        constructor(props) {
            super(props);
        }
 
        render() {

            return (
                <div className="App">
                    <h1>React route</h1>
                    <hr/>
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>
                    <input type="text"/>
                    <Route path="/" component={Home} exact />
                    <Route path="/about" component={About}/>
                </div>
            )
        }
 
    }
 
    export default App;

link helps us generate a tag. It also listens to the click event of a tag, and prevents the default jump behavior of A. at the same time, it triggers the api of html5history, modifies the url, and displays the corresponding components according to the modified url.

At the same time, whether using HashRouter or BrowserRouter, the link component will help us generate the corresponding a tag. We don't need to add \!

Carefully observe that there is a click event in the a tag.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-5
Branch: branch4

commit description:v3.02-5-example02-5 (application scenario (I) - use the BrowserRouter component to solve the problem of lost status)

tag: v3.02-5

2.3.2 application scenario (II)

I'm in a tight situation recently. I want to sell something in the application to subsidize my family

2.3.2.1 status improvement

Component state promotion was mentioned in the previous component. If multiple components need to share a state, then the state is promoted to the common parent component that uses the state.

./BaseApp/Index.js

this.state = {
  items: [
    {
      id: 1,
      name: 'iPhone XR',
      price: 542500
    },
    {
      id: 2,
      name: 'Apple iPad Air 3',
      price: 377700
    },
    {
      id: 3,
      name: 'Macbook Pro 15.4',
      price: 1949900
    },
    {
      id: 4,
      name: 'Apple iMac',
      price: 1629900
    },
    {
      id: 5,
      name: 'Apple Magic Mouse',
      price: 72900
    },
    {
      id: 6,
      name: 'Apple Watch Series 4',
      price: 599900
    }
  ]
}

2.3.2.2 transfer props

<Route exact path='/' component={Home}

If Route uses component to specify components, props cannot be used

2.3.2.2.1 example03

First, we want to display the product list in the home page, so we need to transfer data to this component. At present, our home master is passed to Route as an attribute.

            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
{/*
    In the following way, items are passed to Route, not Home
*/}
<Route path="/" component={Home} exact items={this.state.items} />
// If the data is written by ourselves, our parameters are transferred in the following form:
<Home items={this.state.items} / >

Let's print props in the homepage component. Let's have a look:

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link} from 'react-router-dom';

import Home from './views/Home';
import About from './views/About';

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>
                <nav>
                    <Link to="/">home page</Link>
                    <span> | </span>
                    <Link to="/about">About us</Link>
                </nav>
                <hr/>
                <Route path="/" component={Home} exact items={this.state.items}/>
                <Route path="/about" component={About}/>
            </div>
        )
    }

}

export default App;

react-Novice05\app\src\views\Home.js

import React from 'react';

export default class Home extends React.Component {

    render() {
        console.log(this.props);
        return (
            <div>
                <h2>Product list</h2>
            </div>
        );
    }

}

Xiao Di looked for it for a long time, but she really couldn't find items.

In the above way, items are passed to Route, not Home.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.03
Branch: branch4

commit description:v3.03-example03 (application scenario (2) - how to pass values to component parameters of a routing component?)

tag: v3.03

2.3.2.2.2 Route : render
<Route exact path='/' render={() => <Home items={this.state.items} />} />

The render function is specified through the render attribute. The render attribute value is a function that is specified to render when the route matches.

2.3.2.2.2.1 example04

The above is unsuccessful. How does the routing component pass values to component parameters? Let's revise:

Pass props to the component specified by the component
Route also provides a render attribute, which is passed into a function. The value returned by the function is equivalent to the rendering result of the Component specified by the Component.

    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
    import Home from './views/Home';
    import About from './views/About';

    class App extends React.Component {
 
        constructor(props) {
            super(props);
 
            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
        }
 
        render() {
            return (
                <div className="App">
                    <h1>React route</h1>
                    <hr/>
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>
                    <Route path="/" exact  render={() => {
                        return <div>I am render Come out</div>
                    }} />
                    <Route path="/about" component={About}/>  
                </div>
            )
        }
 
    }
 
    export default App;

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.04-1
Branch: branch4

commit description:v3.04-1-example04-1 (application scenario 2) - how to pass values to component parameters of a routing component? Pass props to the component specified by the component)

tag: v3.04-1

app.js

    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
  
 
    import Home from './views/Home';
    import About from './views/About';

    class App extends React.Component {
 
        constructor(props) {
            super(props);
 
            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
        }
 
        render() {
 
            return (
                <div className="App">
 
                    <h1>React route</h1>
                    <hr/>
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>
                    <Route path="/" exact render={() => {
                        return <Home items={this.state.items} />
                    }} />
                    <Route path="/about" component={About}/>      
                </div>
            )
        }
 
    }
 
    export default App;

src/views/Home.js

import React from 'react';
 
export default class Home extends React.Component {
 
    render() {
        console.log(this.props);
        return (
            <div>
                <h2>Product list</h2>
            </div>
        );
    }
}

Can be abbreviated as:

                    <Route path="/" exact render={() => <Home items={this.state.items} />} />                  

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.04-2
Branch: branch4

commit description:v3.04-2-example04-2 (application scenario 2) - how to pass values to component parameters of a routing component? Pass props to the component specified by the component)

tag: v3.04-2

Perfect list

src/css.css

ul {
    margin: 0;
    padding: 0;
}
 
li {
    list-style: none;
}
 
.item-list li {
    padding: 10px;
    display: flex;
    justify-content: space-between;
    height: 30px;
    line-height: 30px;
    border-bottom: 1px dotted #333;
}
.item-list li.head {
    font-weight: bold;
}
.item-list li span {
    min-width: 200px;
}
 
.pagination {
    margin: 10px;
}
.pagination a {
    margin: 0 5px;
    display: inline-block;
    width: 30px;
    height: 30px;
    background-color: #f4f4f5;
    line-height: 30px;
    text-align: center;
    cursor: pointer;
    color: #606266;
    text-decoration: none;
}
.pagination a:hover {
    color: #409eff;
}
.pagination a.active {
    background-color: #409eff;
    color: #fff;
    cursor: text;
}
.pagination .goto {
    margin: 0 5px;
    box-sizing: border-box;
    width: 80px;
    height: 30px;
    border: 1px solid #dcdfe6;
    outline: none;
    text-align: center;
    vertical-align: top;
}

app.js

    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
    import './css.css';
 
    import Home from './views/Home';
    import About from './views/About';

    class App extends React.Component {
 
        constructor(props) {
            super(props);
 
            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
        }
 
        render() {
 
            return (
                <div className="App">
                    <h1>React route</h1>
                    <hr/>
 
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>
                    <Route path="/" exact render={() => <Home items={this.state.items} />} />
                    <Route path="/about" component={About}/>
                </div>
            )
        }
    }
    export default App;

src/views/Home.js

import React from 'react';
 
import Item from '../components/Item.js';
 
export default class Home extends React.Component {
 
    render() {
 
 
        let {items} = this.props;
 
        return (
            <div>
                <h2>Product list</h2>
 
                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
            </div>
        );
    }
 
}

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";
 
export default class Item extends React.Component{
 
    render() {
        let {item} = this.props;
 
        return(
            <li>
                <span>
                    <a href="">{item.name}</a>
                </span>
                {/*Keep two decimal places*/}
                <span>¥ {(item.price / 100).toFixed(2)}</span>
            </li>
        );
    }
 
}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.04-3
Branch: branch4

commit description:v3.04-3-example04-3 (application scenario (II) - improve the home page list)

tag: v3.04-3

2.3.2.3 rendering list

Home.js

import React from 'react';
 
import {Link} from 'react-router-dom';
 
export default class Home extends React.Component {
 
    render() {
        let {items} = this.props;
 
        return (
            <div>
                <h2>Product list</h2>
                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map(item=>(
                            <li key={item.id}>
                                <span>
                                    <Link to={'/Item/' + item.id}>{item.name}</Link>
                                </span>
                                <span>¥ {(item.price / 100).toFixed(2)}</span>
                            </li>
                        ))
                    }
                </ul>
            </div>
        );
    }
 
}
2.3.2.3.1 example05

Complete the details page

App.js

 
 
    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
    import './css.css';
 
    import Home from './views/Home';
    import About from './views/About';
    import View from "./views/View";
 
    class App extends React.Component {
 
        constructor(props) {
            super(props);
 
            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
        }
 
        render() {
            return (
                <div className="App">
                    <h1>React route</h1>
                    <hr/>
 
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>

                    <Route path="/" exact render={() => <Home items={this.state.items} />} />
 
                    {/*Product details*/}
                    <Route path='/view' component={View}/>
 
                    <Route path="/about" component={About}/>
                </div>
            )
        }
 
    }   
    export default App;

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";
 
export default class Item extends React.Component{
 
    render() {
        let {item} = this.props;
 
        return(
            <li>
                <span>
                    <Link to={"/view/"}>{item.name}</Link>
                </span>
                {/*Keep two decimal places*/}
                <span>¥ {(item.price / 100).toFixed(2)}</span>
            </li>
        );
    }
 
}

src/views/View.js

import React from 'react';
 
export default class View extends React.Component {
 
    render() {
        return(
            <div>
                <h2>Product details </h2>
                <hr/>
                <p>Other details...</p>
            </div>
        );
    }
 
}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.05
Branch: branch4

commit description:v3.05-example05 (application scenario (II) - add the click Details function)

tag: v3.05

How to pass parameters to the details page? The information of an item in the list we clicked should be transferred to the details page.

You may think of uploading from item to home, then to app, and finally to view. It is conceivable that this kind of communication is very disgusting!

If the component is a page component, the data transfer between the two different page components should not be done through the traditional component parent-child communication. The data should be transferred through the page (routing, or loacl storage, or redux. In fact, they are all stored uniformly)

2.3.2.3.2 params

In the route, params refers to the variable part of the path. Here we need to define a new route to display the details of the goods. We want to access the goods with the corresponding id through /item/1, /item/2, /item/... So the following digital part is variable - params. We also call this route: dynamic route

2.3.2.4 dynamic routing

In order to access the dynamic routing address above, we need to configure a special path for the Route component

<Route path='/item/:id' component={Item} />
2.3.2.4.1 path-to-regexp

Path to regexp is a library dedicated to handling URL s. It is used for a regular like string representation

: indicates that the following part is variable, and: the following word is the name of the matched content storage, such as: /item/1, that is, id=1

By default, it provides us with several common character representations: *+

But we can use regular

<Route path='/item/:id(\d+)' component={Item} />

The above indicates that /item/ can only be followed by numbers

2.3.2.4.2 Route : props

After dynamic route matching, we can access the current route matching information through the props attribute of the corresponding component

2.3.2.5 routing components

If a component is accessed directly through routing, we call it: routing component - view component. Other types can be called: business component, UI component, container component

If a component is a routing component, the props attribute of the component will automatically add several routing related attributes

  • History: object, which provides some methods for operating routes, similar to the history object in native JavaScript
  • location: object, through which you can obtain the current route URL information, similar to history in native JavaScript location object
  • match: object, URL information after current route resolution
2.3.2.5.1 example06

Use dynamic routing to transit the page.

2.3.2.5.1.1 example06-1

The following route is dynamic, and the id after ':' indicates that the dynamic part matches the content
Only /view/XXXXX can match the current route

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <Link to="/">home page</Link>
                    <span> | </span>
                    <Link to="/about">About us</Link>
                </nav>
                <hr/>

                <Route path="/" exact render={() => <Home items={this.state.items} />} />
                <Route path='/view/:id' component={View}/>
                <Route path="/about" component={About}/>
            </div>
        )
    }

}

export default App;

We found that http://localhost:3000/view The page cannot be seen. It must be in this form: http://localhost:3000/view/ The parameter page can be displayed only after the "/view/:id" rule page is met. This parameter will be assigned to id in the actual matching. In fact, id is a variable to receive the matching parameters in the route.

But now the parameter can be any value. What if it is only limited to numbers? In fact, you can set rules similar to regular rules. The setting here must be followed by a number and at least one.

<Route path="/view/:id(\d+)" component={View} />

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.06-1
Branch: branch4

commit description:v3.06-1-example06-1 (application scenario (II) - use dynamic routing to transit the page)

tag: v3.06-1

2.3.2.5.1.2 example06-2

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";
 
export default class Item extends React.Component{
 
    render() {
        let {item} = this.props;
 
        return(
            <li>
                <span>
                    <Link to={"/view/" + item.id}>{item.name}</Link>
                </span>
                {/*Keep two decimal places*/}
                <span>¥ {(item.price / 100).toFixed(2)}</span>
            </li>
        );
    }
 
}

Get the content corresponding to the id from the dynamic routing url

src/views/View.js

import React from 'react';
 
export default class View extends React.Component {
 
    render() {
 
        console.log(this.props);
 
        return(
            <div>
                <h2>Product details </h2>
                <p>Other details...</p>
            </div>
        );
    }
 
}

We found that we didn't send content to the props of view, so there were many more things.

BrowserRouter is a container component, in which our App is nested, and it will inject things into the App. Let's look at the pseudo code:

BrowserRouter approximate pseudo code:

    class BrowserRouter extends React.Component {
 
        render() {
            
            // Render subcomponents
 
            return this.props.children; // Return subcomponents
        }
 
    }

App JS with route pseudo code:

    class Route extends React.Component {
 
        render() {
             // Component is the component attribute we write on the label
 			// Add some objects
            this.props.component.props.history;
            this.props.component.props.match;
            this.props.component.props.location;
 
            return this.props.component; // The component attribute we wrote
        }
 
    }

If a component is a routing component (a component directly bound and accessed by the route), the component will be automatically injected (injected by the BrowserRouter container component)

  • History: similar to the (html5)history api, the page can be skipped

  • match: currently accessed routing information

  • Location: equivalent to native location

view.js

import React from 'react';
 
export default class View extends React.Component {
 
    render() {
 
        // console.log(this.props);
        let {id} = this.props.match.params;
        console.log(id)
 
 
        return(
            <div>
                <h2>Product details </h2>
                <p>Other details...</p>
            </div>
        );
    }
 
}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.06-2
Branch: branch4

commit description:v3.06-2-example06-2 (application scenario (2) - use dynamic route transit page - route container component to inject object attributes)

tag: v3.06-2

2.3.2.5.2 match : params
this.props.match.params.id

Note: non routing components do not have routing data

If a component wants to receive both manual incoming props and routing information

<Route path='/item/:id(\d+)' render={props => <Item {...props} items={this.state.items} />} />

Product details

render() {
  let items = this.props.items;
  let id = Number(this.props.match.params.id) || 0;
  let item = items.find(item => item.id === id);
 
  return item ? (
    <div>
      <h2>Product details - {item.name}</h2>
      <dt>ID</dt>
      <dd>{item.id}</dd>
      <dt>name</dt>
      <dd>{item.name}</dd>
      <dt>price</dt>
      <dd>¥ {(item.price / 100).toFixed(2)}</dd>
    </div>
  ) : <div>The product does not exist!</div>;
}
2.3.2.5.2.1 example07

At present, we can get the id through the url, but where does the data required by the view component come from? Now we need to take the id, find the corresponding item in the data, and then display it. In the later stage, you may directly send a request to the back end to ask for data, that is, the front end does not do it but sends a request to the back end.

app.js

 
 
    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
    import './css.css';
 
    import Home from './views/Home';
    import About from './views/About';
    import View from "./views/View";
 
 
    class App extends React.Component {
 
        constructor(props) {
            super(props);
 
            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
        }
 
        render() {
 
            return (
                <div className="App">
                    <h1>React route</h1>
                    <hr/>
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>
                    <Route path="/" exact render={() => <Home items={this.state.items} />} />
                    <Route path="/view/:id(\d+)" render={() => {
                        return <View />
                    }} />
                    <Route path="/about" component={About}/>
                </div>
            )
        }
 
    }
 
    export default App;

Where does the data required by the view component come from??????????????????

view.js

import React from 'react';
 
export default class View extends React.Component {
 
    render() {

        console.log(this.props);
        let {id} = this.props.match.params;
        console.log(id)
 
        return(
            <div>
                <h2>Product details </h2>
                <p>Other details...</p>
            </div>
        );
    }
 
}

Cause of error (hang): the View is no longer a routing component, which means that the Route related information injected by Route is gone, that is, the history, match, location and other parameter objects are gone.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.07-1
Branch: branch4

commit description:v3.07-1-example07-1 (application scenario (II) - improve the details page, jump to the page and report an error)

tag: v3.07-1

If the render function is used, the history, match and other objects injected by the route are passed to the render function as parameters
render is actually a functional component

                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View />
                        console.log(props);
                    }} />
                    <Route path="/about" component={About}/>

src/App.js

 
 
    import React from 'react';
 
    import {Route, Link} from 'react-router-dom';
 
    import './css.css';
 
    import Home from './views/Home';
    import About from './views/About';
    import View from "./views/View";
 
    class App extends React.Component {
 
        constructor(props) {
            super(props);
 
            this.state = {
                items: [
                    {
                        id: 1,
                        name: 'iPhone XR',
                        price: 542500
                    },
                    {
                        id: 2,
                        name: 'Apple iPad Air 3',
                        price: 377700
                    },
                    {
                        id: 3,
                        name: 'Macbook Pro 15.4',
                        price: 1949900
                    },
                    {
                        id: 4,
                        name: 'Apple iMac',
                        price: 1629900
                    },
                    {
                        id: 5,
                        name: 'Apple Magic Mouse',
                        price: 72900
                    },
                    {
                        id: 6,
                        name: 'Apple Watch Series 4',
                        price: 599900
                    }
                ]
            }
        }
 
        render() {
            return (
                <div className="App">
                  
 
                    <nav>
                        <Link to="/">home page</Link>
                        <span> | </span>
                        <Link to="/about">About us</Link>
                    </nav>
                    <hr/>
                    <Route path="/" exact render={() => <Home items={this.state.items} />} />
 
                    <Route path="/view/:id(\d+)" render={(props) => {
                        // es5 is too long
                        // return <View match={props.match} history={props.history} location={props.location} />
                        // es6 is concise in writing, and deconstructs (extension operator)
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/about" component={About}/>
                </div>
            )
        }
 
    }
 
    export default App;

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";
 
export default class Item extends React.Component{
 
    render() {
        let {item} = this.props;
 
        return(
            <li>
                <span>
                    <Link to={"/view/" + item.id}>{item.name}</Link>
                </span>
                {/*Keep two decimal places*/}
                <span>¥ {(item.price / 100).toFixed(2)}</span>
            </li>
        );
    }
 
}

src/views/View.js

import React from 'react';
 
export default class View extends React.Component {
 
    render() {

        // deconstruction
        let {items, match: {params: {id}}} = this.props;
        id = Number(id);
 
        let item = items.find( v => v.id === id );
 
        console.log(items, id, item);
 
        return(
            <div>
                <h2>Product details - {item.name}</h2>
                <p>Other details...</p>
            </div>
        );
    }
 
}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.07-2
Branch: branch4

commit description:v3.07-2-example07-2 (application scenario (II) - improve the details page and jump to the final version of the page)

tag: v3.07-2

2.3.2.6 communication summary

  • Get the content corresponding to the id from the dynamic routing url

  • Where does the data required by the view component come from?????????????????? (it must involve two locations, from a to b. if there is only one component, there is no question about where the component data comes from, that is, the communication problem.)

  • How components get data:

    • The (parameter transfer) parent-child communication of a component, and the data is transferred in by the parent-level parameter transfer
    • Through the url corresponding to the component, the component must be associated with the url. We need to mount the data required by the component to the url, and then check the data at a certain location on the url when the component renders
    • Get through the back end: send requests (ajax) in some life cycles of components
    • Through local storage (not recommended because of its size limit)
    • Global variables (memory), such as attaching data to the window and fetching data from the window when rendering data (generally, it is not recommended. It is similar to redux. Unless there is a better way to manage and maintain global variables, it is easy to mess up)
    • ... (there are many other methods, but only one point is concerned. For those involving data communication, the current accessible methods are as follows)
  • Data communication mode

    • If the components are not nested (for example, in this example), if we choose scheme 1, there will be too many communication steps involved. You need to transfer them layer by layer, which will be very cumbersome
    • In fact, the two components are nested, that is, parent-child relationship or sibling relationship (their common parent is at the upper level, not too many). Scheme 1 can be used
    • Scheme 2 is actually suitable for the case where two components do not exist at the same time. If there is a view, there is no item, that is, two components are not displayed at the same time in a page. The two components do not meet each other, but the view data can be brought to the item from the url, but only a small batch of data

2.3.3 application scenario (III)

I want to add a function that users can choose to display according to the commodity price

2.3.3.1 sorting switching through JavaScript

Home.js

...
this.state = {
      sort: 'desc'
 
      this.changeSort = this.changeSort.bind(this);
}
...
changeSort({target: {value: sort}}) {
      this.setState({sort});
}
...
render() {
      let {items} = this.props;
      let {sort} = this.state;
      items = items.sort((a, b) => sort === 'asc'  ? a.price - b.price : b.price - a.price);
      return(
          ...
          <select value={sort} onChange={this.changeSort}>
          <option value="desc">From high to low</option>
          <option value="asc">From low to high</option>
          </select>
          ...
    )
}

Problem: refresh page and share URL will lose status

2.3.3.1.1 example08

js implementation sorting

2.3.3.1.1.1 example08-1

src/views/Home.js

import React from 'react';
 
import Item from '../components/Item.js';
 
export default class Home extends React.Component {
 
 
    render() {
 
 
        let {items} = this.props;
 
        items = items.sort( (a, b) => {
            return b.price - a.price;
        } );
 
 
        return (
            <div>
                <h2>Product list</h2>
 
                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
 
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
            </div>
        );
    }
 
}

Descending order:

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.08-1
Branch: branch4

commit description:v3.08-1-example08-1 (application scenario (III) - users can choose to display according to the commodity price -js implementation - simple descending order)

tag: v3.08-1

2.3.3.1.1.2 example08-2
import React from 'react';
 
import Item from '../components/Item.js';
 
export default class Home extends React.Component {
 
    constructor(props) {
        super(props);
 
        this.sort = this.sort.bind(this);
    }
 
    sort(e) {
        console.log(e.target.value);
 
        let {items} = this.props;
 
        items = items.sort( (a, b) => {
            return 'desc' === e.target.value ? b.price - a.price : a.price - b.price;
        } );
 
        this.setState({
            items
        });
    }
 
    render() {
 
        let {items} = this.props;
 
        return (
            <div>
                <h2>Product list</h2>
 
                <select onChange={this.sort}>
                    <option value="desc">Descending order</option>
                    <option value="asc">Ascending order</option>
                </select>
 
                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
            </div>
        );
    }
 
}

Found no default sort set.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.08-2
Branch: branch4

commit description:v3.08-2-example08-2 (application scenario (III) - the user can select and display according to the commodity price -js implementation - Implementation of switching sorting)

tag: v3.08-2

2.3.3.1.1.3 example08-3

We need to set the default sorting status first, which can be encapsulated as follows:

import React from 'react';
 
import Item from '../components/Item.js';
 
export default class Home extends React.Component {
 
    constructor(props) {
        super(props);
 
        // Default descending order, assigned to state
        this.state = {
            items: this.doSort('desc')
        };
 
        this.sort = this.sort.bind(this);
    }
 
    sort(e) {
        console.log(e.target.value);
 
        let items = this.doSort(e.target.value);
        this.setState({
            items
        });
    }
 
    doSort(type = 'desc') {
        let {items} = this.props;
 
        return items.sort( (a, b) => {
            return 'desc' === type ? b.price - a.price : a.price - b.price;
        } );
    }
 
 
    render() {
        // Take the items sorted by default
        let {items} = this.state;
 
        return (
            <div>
                <h2>Product list</h2>
 
                <select onChange={this.sort}>
                    <option value="desc">Descending order</option>
                    <option value="asc">Ascending order</option>
                </select>
 
                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
            </div>
        );
    }
 
}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.08-3
Branch: branch4

commit description:v3.08-3-example08-3 (application scenario (III) - the user can select and display according to the commodity price -js implementation - switch sorting and add default descending sorting)

tag: v3.08-3

Problems:

1. If there is a lot of data, it needs to be paged.

2. If the sorted pages are shared with others, and the pages opened by others are sorted in descending order by default, the pages may be different. Therefore, it is better to keep the sorting status here (the sorting status can also be determined through the url). (the sorting function should not affect the url address itself, otherwise the route cannot be seen clearly, that is, it does not affect the url resources and can carry data, so queryString is required.)

2.3.3.2 sorting switching through routing

2.3.3.2.1 queryString

Usually we put the URL? The following content is called queryString, which is displayed in react JS, we can use this Props Location Search. Its value is a string. The format is:? K1=v1&k2=v2. For the convenience of operation, we convert it into object form

/The api/users address represents all the data related to users. Assuming that there are 10000 pieces of data and you only want to see some of them, you need to bring query conditions, such as: /api/users? Page=1 querystring actually obtains resources with certain and conditions

Back to the point: we can set localhost:3000/?sort=desc

2.3.3.2.2 URLSearchParams

A class of URLSearchParams is built in the native JavaScript, which allows us to easily operate queryString

let {location: {search}} = this.props;
let qs = new URLSearchParams(search);
let sort = qs.get('sort');

2.3.3.3 extension

2.3.3.3.1 qs Library

https://www.npmjs.com/package/qs

2.3.3.3.2 installation
npm i -S qs
2.3.3.3.3 use

search: parsed string

ignoreQueryPrefix: whether to ignore the question mark

import queryString from 'qs';
 
let qsTest = queryString.parse(search, {ignoreQueryPrefix: true});
let sort = qsTest.sort;
2.3.3.3.4 switch routes through JavaScript programming

In addition to using the <link> component to click to jump the route like a, we can also switch the route through programming (JavaScript)

let {history} = this.props;
<select defaultValue={sort} onChange={({target:{value}})=>{
    history.push('/?sort=' + value);
  }}>
  <option value="desc">From high to low</option>
  <option value="asc">From low to high</option>
</select>
2.3.3.3.5 example09

Sort switching through routing

2.3.3.3.5.1 example09-1

home.js

// Get from querystring of url
        console.log(window.location);

        // Get from querystring of url
        console.log(window.location.search);

Let's intercept the question mark!

    // Get from querystring of url
    console.log(window.location.search.substring(1));

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-1
Branch: branch4

commit description:v3.09-1-example09-1 (application scenario (III) - users can choose to display according to the commodity price - get querystring)

tag: v3.09-1

2.3.3.3.5.2 example09-2

The above code is in the format of key=value. How can we get value? We can turn it into an object or use a third-party library (such as the qs Library).

Native method:

    let queryString = window.location.search.substring(1);
    // Function: convert queryString to object form
    let qs = new URLSearchParams(queryString);
    console.log(qs);

Use the get method to get values:

    let queryString = window.location.search.substring(1);
    // Function: convert queryString to object form
    let qs = new URLSearchParams(queryString);
    console.log(qs.get('sort'));

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-2
Branch: branch4

commit description:v3.09-2-example09-2 (application scenario (III) - the user can choose to display according to the commodity price - the native js gets the value in querystring)

tag: v3.09-2

2.3.3.3.5.3 example09-3

queryString: parsed string

ignoreQueryPrefix: whether to ignore the question mark

    import qs from 'qs';        

    let queryString = window.location.search.substring(1);
    // Function: convert queryString to object form
    let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});
    let sort = qsTest.sort;
    console.log(sort);

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-3
Branch: branch4

commit description:v3.09-3-example09-3 (application scenario (III) - the user can choose to display according to the commodity price -qs library obtains the value in querystring)

tag: v3.09-3

2.3.3.3.5.4 example09-4

The above queryString is obtained through native js, and can also be obtained through component objects. Just now we talked about routing component rendering. If a component is a routing component (a component directly bound and accessed by a route), the component will be automatically injected:

  • History: similar to the (html5)history api, the page can be skipped
  • match: currently accessed routing information
  • Location: equivalent to native location

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <Link to="/">home page</Link>
                    <span> | </span>
                    <Link to="/about">About us</Link>
                </nav>
                <hr/>

                <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                <Route path="/view/:id(\d+)" render={(props) => {
                    return <View {...props} items={this.state.items} />
                }} />
                <Route path="/about" component={About}/>
            </div>
        )
    }

}

export default App;

react-Novice05\app\src\views\Home.js

import React from 'react';

import Item from '../components/Item.js';
import qs from 'qs';

export default class Home extends React.Component {

    constructor(props) {
        super(props);

        // Default descending order, assigned to state
        this.state = {
            items: this.doSort('desc')
        };

        this.sort = this.sort.bind(this);
    }

    sort(e) {
        console.log(e.target.value);

        let items = this.doSort(e.target.value);
        this.setState({
            items
        });
    }

    doSort(type = 'desc') {
        let {items} = this.props;

        return items.sort( (a, b) => {
            return 'desc' === type ? b.price - a.price : a.price - b.price;
        } );
    }

    render() {

        // Take the items sorted by default
        let {items} = this.state;

        console.log(this.props)

        let queryString = window.location.search.substring(1);
        // Function: convert queryString to object form
        let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});
        let sort = qsTest.sort;

        return (
            <div>
                <h2>Product list</h2>

                <select onChange={this.sort}>
                    <option value="desc">Descending order</option>
                    <option value="asc">Ascending order</option>
                </select>

                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
            </div>
        );
    }

}

The value can be obtained in the search of location.

        let {location} = this.props;

        // let queryString = window.location.search.substring(1);
        let queryString = location.search.substring(1);
        // Function: convert queryString to object form
        let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});
        let sort = qsTest.sort;
        console.log(sort);

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-4
Branch: branch4

commit description:v3.09-4-example09-4 (application scenario (3) - the user can choose to display according to the commodity price - obtain queryString through component object)

tag: v3.09-4

2.3.3.3.5.5 example09-5

Improve the sorting switch tab function:

When the user selects in the select tab, we do not want it to be a controlled component (the value here is bound to state). At present, the value of the sort variable is not in the component. In fact, when the user selects sorting, it is not necessary to modify the value of the sort variable, just skip the page. Therefore, we can bind it with a defaultvalue attribute (binding uncontrolled).

import React from 'react';

import Item from '../components/Item.js';
import qs from 'qs';

export default class Home extends React.Component {

    constructor(props) {
        super(props);

        // Default descending order, assigned to state
        this.state = {
            items: this.doSort('desc')
        };

        this.sort = this.sort.bind(this);
    }

    sort(e) {
        // let items = this.doSort(e.target.value);
        // this.setState({
        //     items
        // });
        // Jump page
        let {history} = this.props;
        history.push(`/?sort=${e.target.value}`)
    }

    doSort(type = 'desc') {
        let {items} = this.props;

        return items.sort( (a, b) => {
            return 'desc' === type ? b.price - a.price : a.price - b.price;
        } );
    }

    render() {

        // Take the items sorted by default
        let {items} = this.state;
        let {location} = this.props;

        // let queryString = window.location.search.substring(1);
        let queryString = location.search.substring(1);
        // Function: convert queryString to object form
        let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});
        let sort = qsTest.sort || 'desc';

        this.doSort(sort);

        return (
            <div>
                <h2>Product list</h2>

                <select defaultValue={sort} onChange={this.sort}>
                    <option value="desc">Descending order</option>
                    <option value="asc">Ascending order</option>
                </select>

                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
            </div>
        );
    }

}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-5
Branch: branch4

commit description:v3.09-5-example09-5 (application scenario (III) - users can choose to display according to the commodity price - improve the sorting and switching tab function final version)

tag: v3.09-5

2.3.4 application scenario (IV)

Now, I want to highlight the navigation at the top of the page to identify the current page. At this time, we can use the NavLink component provided by react router DOM to implement

2.3.4.1 NavLink components

NavLink is similar to Link, but it provides two special properties to handle page navigation

2.3.4.1.1 activeStyle

Activate the style in activeStyle when the current URL matches the to in NavLink

2.3.4.1.2 activeClassName

Similar to activeStyle, but with className activated

2.3.4.1.3 isActive (similar to callback, which can handle some more complex situations)

By default, the settings of URL and to are matched. The activation logic can be customized through isActive. isActive is a function that returns a Boolean value

index.js

<NavLink to="/" activeStyle={{color:'red'}} isActive={(match, location) => {
    return match || location.pathname.startsWith('/item')
}} exact>Home</NavLink>
<span> | </span>
<NavLink to="/about" activeStyle={{color:'red'}} exact>About</NavLink>
2.3.4.1.4 exact

Exact match

2.3.4.2 example10

NavLink assembly (navigation assembly)

2.3.4.2.1 example10-1

activeStyle: activate the style in activeStyle when the current URL matches the to in NavLink

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NavLink from "react-router-dom/modules/NavLink";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <NavLink to="/" activeStyle={{color: 'red'}}>home page</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>
                <hr/>

                <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                <Route path="/view/:id(\d+)" render={(props) => {
                    return <View {...props} items={this.state.items} />
                }} />
                <Route path="/about" component={About}/>
            </div>
        )
    }

}

export default App;

However, there are obvious problems! Why is the home page still highlighted after clicking about us! Because by default, it belongs to a kind of fuzzy matching, that is, inexact matching. At this time "/about" also meets the "/" rule, so "/about" will match both!

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.10-1
Branch: branch4

commit description:v3.10-1-example10-1 (application scenario (IV) - navigation at the top of the page plus highlighting effect - not exactly matched)

tag: v3.10-1

2.3.4.2.2 example10-2

Perfect exact match:

Learn to read documents

import React from 'react';

import {Route, Link, NavLink } from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <NavLink to="/" activeStyle={{color: 'red'}} exact={true}   >home page</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>
                <hr/>

                <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                <Route path="/view/:id(\d+)" render={(props) => {
                    return <View {...props} items={this.state.items} />
                }} />
                <Route path="/about" component={About}/>
            </div>
        )
    }

}

export default App;

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.10-2
Branch: branch4

commit description:v3.10-2-example10-2 (application scenario (IV) - navigation at the top of the page plus highlighting effect - exact matching)

tag: v3.10-2

2.3.4.2.3 example10-3

isActive (similar to callback, which can handle some more complex situations):

By default, the settings of URL and to are matched. The activation logic can be customized through isActive. isActive is a function that returns a Boolean value

When is the isActive attribute used?

The principle of example10-2 above is that the url and to attributes are compared according to certain rules. If the rules are satisfied after comparison, the set style will be activated.

If we click the details (i.e. visit the inner page), the url at this time does not match the above to attribute. How can we highlight it? We can't use it at this time. We have to make our own rules.

<nav>
    <NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {
        // match current matching location current address bar information
        console.log(match, location);
    }}>home page</NavLink>
    <span> | </span>
    <NavLink to="/about" activeStyle={{color: 'red'}} >About us</NavLink>
</nav>

When you click the details page, match is null, which means that there is no match currently, that is, the currently accessed address does not match (with the current attribute to).

                <nav>
                    <NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {
                        // match current matching location current address bar information
                        // console.log(match, location);
                        // If match is true, no processing is required. Otherwise, it starts with'/view'
                        return match || location.pathname.startsWith('/view');
                    }}>home page</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.10-3
Branch: branch4

commit description:v3.10-3-example10-3 (application scenario (IV) - navigation at the top of the page plus highlighting effect - Complete)

tag: v3.10-3

2.3.5 application scenarios (V)

When users access non-existent routes, we need to provide a feedback page, that is, 404 (friendly page)

index.js

<Route exact path='/' render={props => <Home {...props} items={this.state.items} />} />
<Route path='/about' component={About} />
<Route path='/item/:id(\d+)' render={props => <Item {...props} items={this.state.items} />} />
{/*NotFound*/}
<Route component={NotFound} />

NotFound.js

import React from 'react';
 
export default function NotFound() {
    return (
        <div>
            Not Found
        </div>
    );
}

By default, react JS will render all matching routing components. In the above case, when we access any route (e.g.: /about), it will also match the NotFound route component rendering

2.3.5.1 Switch components

This component renders only the first matched component

<Switch>
      <Route exact path='/' render={props => <Home {...props} items={this.state.items} />} />
    <Route path='/about' component={About} />
    <Route path='/item/:id(\d+)' render={props => <Item {...props} items={this.state.items} />} />
    {/*NotFound*/}
    <Route component={NotFound} />
</Switch>

2.3.5.2 example11

Implementation 404 (friendly page)

2.3.5.2.1 example11-1

src/views/NotFound.js

import React from 'react';
 
export default class NotFound extends React.Component {
 
 
    render() {
        return (
            <div>
                <h1>Not Found - 404</h1>
            </div>
        );
    }
 
}

App.js

<Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/about" component={About}/>
                    <Route component={NotFound} />

Each page contains 404 page components. Because the path is not set, it means that the actual default is a wildcard, which can match any path, that is, each page contains a 404 page component.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.11-1
Branch: branch4

commit description:v3.11-1-example11-1 (application scenario (V) - implementation 404 (friendly page), problems encountered)

tag: v3.11-1

2.3.5.2.2 example11-2

The default react route is penetrating

For example, in the switch statement in js, if break is removed here, b and c will be printed. After the value of the first variable a is satisfied, if there is no break, continue to penetrate. Our concept of route penetration is similar to this, so all pages are displayed.

let a = 2;
switch (a) {
    case 1:
        console.log('a');
        // break;
    case 2:
        console.log('b');
        // break;
    case 3:
        console.log('c');
        // break;
}

We use the switch component to solve the above problems

                <Switch>
                    <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/about" component={About}/>
                    <Route component={NotFound} />
                </Switch>

If the notfound component is placed at the top, all pages are 404. It should be because it is universal, no rules are set, and all pages comply with the rules. Therefore, great attention should be paid to this order in actual development. (this code is relatively simple, so Xiaodi doesn't need git.)

                <Switch>
                    <Route component={NotFound} />
                    <Route path="/" exact render={(props) => {
                        return <Home items={this.state.items} {...props} />
                    }} />
 
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/about" component={About}/>
 
                </Switch>

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.11-2
Branch: branch4

commit description:v3.11-2-example11-2 (application scenario (V) - implementation 404 (friendly page), complete)

tag: v3.11-2

2.3.6 application scenarios (VI)

Now, we want to add a shopping cart function to users

index.js

// Add a connection
<NavLink to="/cart" activeStyle={{color:'red'}} exact>Cart</NavLink>

Cart.js

// Shopping cart components
import React from 'react';
 
export default class Cart extends React.Component {
 
    render() {
        return(
            <div>
                shopping cart
            </div>
        );
    }
 
}

We also need a user system, such as registration and login

index.js

// Simulate a state that adds login user status
this.state = {
      users: [
      {
        id: 1,
        username: 'zs',
        password: '123'
      },
      {
        id: 2,
        username: 'ls',
        password: '123'
      },
      {
        id: 3,
        username: 'ww',
        password: '123'
      },
      {
        id: 4,
        username: 'gg',
        password: '123'
      }
    ],
    userInfo: {
          id: 0,
          username: ''
    },
      ...
}
 
// Add a login link
{
      this.state.userInfo.id > 0 ? (
              <span>{this.state.userInfo.username}</span>
      ) : (
            <NavLink to='/login' activeStyle={{color:'red'}} exact>Login</NavLink>
      )
}

2.3.6.1 example12

Implement the shopping interface

react-Novice05\app\src\views\Cart.js

import React from 'react';

export default class Cart extends React.Component {

    render() {
        return(
            <div>
                shopping cart
            </div>
        );
    }

}

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link, NavLink, Switch} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {
                        // match current matching location current address bar information
                        // console.log(match, location);
                        // If match is true, no processing is required. Otherwise, it starts with'/view'
                        return match || location.pathname.startsWith('/view');
                    }}>home page</NavLink>
                    <span> | </span>
                    <NavLink to="/cart" activeStyle={{color:'red'}} exact>shopping cart</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>
                <hr/>
                <Switch>
                    <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/cart" component={Cart}/>
                    <Route path="/about" component={About}/>
                    <Route component={NotFound} />
                </Switch>
            </div>
        )
    }

}

export default App;

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.12
Branch: branch4

commit description:v3.12-example12 (application scenario (VI) - Implementing the shopping interface)

tag: v3.12

2.3.6.2 Redirect component

Users who are not logged in cannot access the shopping cart, so we need to add user authority verification (authentication) when accessing the shopping cart. If they are not logged in, they will jump to login

index.js

<Route path='/cart' render={props => {
    if (this.state.userInfo.uid > 0) {
              return <Cart />;
    } else {
              // return <Login />;
              return <Redirect to='/login' />;
    }
}}  />
2.3.6.2.1 to

Set URL for jump

Login code

// index.js
login({username, password}) {
  return new Promise( (resolve, reject) => {
    if (!username || !password) {
      reject('Please enter user name and password');
    }
 
    let user = this.state.users.find(user => user.username === username && user.password === password);
    if ( !user ) {
      reject('The user does not exist or the password is incorrect');
    }
 
    this.setState({
      userInfo: {
        id: user.id,
        username: user.username
      }
    });
 
    resolve('Login successful');
  } );
}
...
<Route path='/login' component={props => {
    return <Login {...props} onLogin={this.login.bind(this)} />;
}} />
 
// login.js
import React from 'react';
 
export default class Login extends React.Component {
 
    constructor(...props) {
        super(...props);
 
        this.login = this.login.bind(this);
 
        this.usernameRef = React.createRef();
        this.passwordRef = React.createRef();
    }
 
    login() {
        let {onLogin, history: {push}} = this.props;
 
        if (typeof onLogin === 'function') {
            onLogin({
                username: this.usernameRef.current.value,
                password: this.passwordRef.current.value
            }).then(msg=>{
                alert(msg);
                push('/');
            }).catch(e=>alert(e));
        }
    }
 
    render() {
        return(
            <div>
                <p>
                    User name:<input type="text" ref={this.usernameRef} />
                </p>
                <p>
                    Password:<input type="password" ref={this.passwordRef} />
                </p>
                <p>
                    <button onClick={this.login}>Login</button>
                </p>
            </div>
        );
    }
 
}
2.3.6.2.2 example13

However, according to the demand, the shopping cart function can only be provided after login. We will not implement a complete login registration for the time being, but simulate one for the time being.

When we visit the shopping cart, we can no longer directly visit it as above, but judge the users.

react-Novice05\app\src\views\Login.js

import React from 'react';

import {Route, Link, NavLink, Switch} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";
import Redirect from "react-router-dom/es/Redirect";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            // User information
            userInfo: {
                id: 0,
                username: ''
            },

            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {
                        // match current matching location current address bar information
                        // console.log(match, location);
                        // If match is true, no processing is required. Otherwise, it starts with'/view'
                        return match || location.pathname.startsWith('/view');
                    }}>home page</NavLink>
                    <span> | </span>
                    <NavLink to="/cart" activeStyle={{color:'red'}} exact>shopping cart</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>
                <hr/>
                <Switch>
                    <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/cart" component={() => {
                        if (this.state.userInfo.id > 0) {
                            return <Cart />;
                        } else {
                            // Redirection component
                            return <Redirect to='/login' />;
                        }
                    }}/>
                    <Route path="/login" component={Login}/>
                    <Route path="/about" component={About}/>
                    <Route component={NotFound} />
                </Switch>
            </div>
        )
    }

}

export default App;

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link, NavLink, Switch} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";
import Redirect from "react-router-dom/es/Redirect";
import Login from "./views/Login";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            // User information
            userInfo: {
                id: 0,
                username: ''
            },

            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {
                        // match current matching location current address bar information
                        // console.log(match, location);
                        // If match is true, no processing is required. Otherwise, it starts with'/view'
                        return match || location.pathname.startsWith('/view');
                    }}>home page</NavLink>
                    <span> | </span>
                    <NavLink to="/cart" activeStyle={{color:'red'}} exact>shopping cart</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>
                <hr/>
                <Switch>
                    <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/cart" component={() => {
                        if (this.state.userInfo.id > 0) {
                            return <Cart />;
                        } else {
                            // Redirection component
                            return <Redirect to='/login' />;
                        }
                    }}/>
                    <Route path="/login" activeStyle={{color:'red'}} exact component={Login}/>
                    <Route path="/about" component={About}/>
                    <Route component={NotFound} />
                </Switch>
            </div>
        )
    }

}

export default App;

        this.state = {
            // User information
            userInfo: {
                id: 1,
                username: ''
            },
            ......
        }

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.13
Branch: branch4

commit description:v3.13-example13 (application scenario (VI) - add login permission control to the shopping interface)

tag: v3.13

2.3.7 application scenarios (VII)

With the increase of products, so much data can not be displayed all at once, so we add a paging function to the display of goods. The paging component is a functional component.

// Pagination.js
import React from 'react';
import PropTypes from 'prop-types';
 
import {withRouter, Link} from 'react-router-dom';
 
class Pagination extends React.Component {
 
    static defaultProps = {
        pages: 1,
        page: 1
    }
 
    static propTypes = {
        pages: PropTypes.number,
        page: PropTypes.number
    }
 
    render() {
 
        let {pages, page, history: {push}} = this.props;
        // console.log(this.props);
 
        return (
            <div className="pagination">
                {
                    (new Array(pages)).fill('').map((v, i) => {
                        return (
                            <Link
                                key={++i}
                                className={i === page ? 'active' : ''}
                                to={'/'+i}
                            >
                                {i}
                            </Link>
                        );
                    })
                }
                go to
                <input type="text" className="goto" onKeyDown={({target:{value}})=>{
                    if (value !== '') {
                        push('/' + value);
                    }
                }} />
                page
            </div>
        );
    }
 
}
 
export default withRouter(Pagination);

2.3.7.1 withRouter component (high-order component)

If a component is not a route binding component, there are no route related objects in its props. Although we can pass in parameters, it will be particularly cumbersome if the structure is complex. Fortunately, we can inject routing objects through the withRouter method.

2.3.7.2 example14

Realize paging function.

2.3.7.2.1 example14-1

Paging frame.

react-Novice05\app\src\components\Pagination.js

import React from 'react';
import PropTypes from 'prop-types';

import {Link, withRouter} from 'react-router-dom';

class Pagination extends React.Component {

    static defaultProps = {
        pages: 1, // PageCount 
        page: 1 // Current page
    }

    // Attribute validation
    static propTypes = {
        pages: PropTypes.number,
        page: PropTypes.number
    }

    render() {
        let {pages, page} = this.props;

        return (
            // Render a label according to the current page
            <div className="pagination">
                {
                    (new Array(pages)).fill('').map((v, i) => {
                        return (
                            <Link
                                key={++i}
                                // Highlight current page
                                className={i === page ? 'active' : ''}
                                to={'/'+i}
                            >
                                {i}
                            </Link>
                        );
                    })
                }
                go to
                <input type="text" className="goto" onKeyDown={e=>{

                }} />
                page
            </div>
        );
    }

}
export default Pagination;

react-Novice05\app\src\App.js

import React from 'react';

import {Route, Link, NavLink, Switch} from 'react-router-dom';

import './css.css';

import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";
import Redirect from "react-router-dom/es/Redirect";
import Login from "./views/Login";
import Pagination from "./components/Pagination";

class App extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            // User information
            userInfo: {
                id: 1,
                username: ''
            },

            items: [
                {
                    id: 1,
                    name: 'iPhone XR',
                    price: 542500
                },
                {
                    id: 2,
                    name: 'Apple iPad Air 3',
                    price: 377700
                },
                {
                    id: 3,
                    name: 'Macbook Pro 15.4',
                    price: 1949900
                },
                {
                    id: 4,
                    name: 'Apple iMac',
                    price: 1629900
                },
                {
                    id: 5,
                    name: 'Apple Magic Mouse',
                    price: 72900
                },
                {
                    id: 6,
                    name: 'Apple Watch Series 4',
                    price: 599900
                }
            ]
        }
    }

    render() {
        return (
            <div className="App">
                <h1>React route</h1>
                <hr/>

                <nav>
                    <NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {
                        // match current matching location current address bar information
                        // console.log(match, location);
                        // If match is true, no processing is required. Otherwise, it starts with'/view'
                        return match || location.pathname.startsWith('/view');
                    }}>home page</NavLink>
                    <span> | </span>
                    <NavLink to="/cart" activeStyle={{color:'red'}} exact>shopping cart</NavLink>
                    <span> | </span>
                    <NavLink to="/about" activeStyle={{color: 'red'}}>About us</NavLink>
                </nav>
                <hr/>
                <Switch>
                    <Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} />
                    <Route path="/view/:id(\d+)" render={(props) => {
                        return <View {...props} items={this.state.items} />
                    }} />
                    <Route path="/cart" component={() => {
                        if (this.state.userInfo.id > 0) {
                            return <Cart />;
                        } else {
                            // Redirection component
                            return <Redirect to='/login' />;
                        }
                    }}/>
                    <Route path="/login" activeStyle={{color:'red'}} exact component={Login}/>
                    <Route path="/about" component={About}/>
                    <Route component={NotFound} />
                </Switch>

                <hr/>
                <Pagination page={1} pages={10} />
            </div>
        )
    }

}

export default App;

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-1
Branch: branch4

commit description:v3.14-1-example14-1 (application scenario (VII) - page box)

tag: v3.14-1

2.3.7.2.2 example14-2

Add paging and sorting to the url

For example: localhost/page=2&sort=desc

The above paging component is written in the wrong position and should be written in the home component. Otherwise, the lower part of our component will also be paged.

react-Novice05\app\src\views\Home.js

import React from 'react';

import Item from '../components/Item.js';
import qs from 'qs';
import Pagination from "../components/Pagination";

export default class Home extends React.Component {

    constructor(props) {
        super(props);

        // Default descending order, assigned to state
        this.state = {
            items: this.doSort('desc')
        };

        this.sort = this.sort.bind(this);
    }

    sort(e) {
        // let items = this.doSort(e.target.value);
        // this.setState({
        //     items
        // });
        // Jump page
        let {history} = this.props;
        history.push(`/?sort=${e.target.value}`)
    }

    doSort(type = 'desc') {
        let {items} = this.props;

        return items.sort( (a, b) => {
            return 'desc' === type ? b.price - a.price : a.price - b.price;
        } );
    }

    render() {

        // Take the items sorted by default
        let {items} = this.state;
        let {location} = this.props;

        // let queryString = window.location.search.substring(1);
        let queryString = location.search.substring(1);
        // Function: convert queryString to object form
        let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});
        let sort = qsTest.sort || 'desc';

        this.doSort(sort);
        let page = Number(qsTest.page) || 1;

        return (
            <div>
                <h2>Product list</h2>

                <select defaultValue={sort} onChange={this.sort}>
                    <option value="desc">Descending order</option>
                    <option value="asc">Ascending order</option>
                </select>

                <ul className="item-list">
                    <li className="head">
                        <span>name</span>
                        <span>price</span>
                    </li>
                    {
                        items.map( item => <Item item={item} key={item.id} /> )
                    }
                </ul>
                <hr/>

                <div>
                    <Pagination page={page} pages={10} />
                </div>
            </div>
        );
    }

}

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-2
Branch: branch4

commit description:v3.14-2-example14-2 (application scenario (VII) - page box, which should be placed in Home)

tag: v3.14-2

2.3.7.2.3 example14-3

Improve the paging function of jumping to a page.

react-Novice05\app\src\components\Pagination.js

                {/*Improve the function of paging to jump to a page*/}
                <input type="text" className="goto" onKeyDown={e=>{
                    if (e.target.value !== '' && e.keyCode == 13) {
                        // Jump page: refresh url
                        history.push('/?page=' + e.target.value);
                    }
                }} />

The prompt indicates that the push attribute cannot be read. This indicates that the history attribute is actually undefined. There is a problem with history here. The current paging component is nested in another page component, so there is no routing object.

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-3
Branch: branch4

commit description:v3.14-3-example14-3 (application scenario (7) - improve the paging function of jumping to a page, but an error is reported)

tag: v3.14-3

2.3.7.2.4 example14-4

Because the home component has a routing object, just pass the history of the home component.

                <div>
                    <Pagination history={this.props.history} page={page} pages={10} />
 
                    {/*<Pagination page={page} pages={10} />*/}
                </div>

Reference: https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-4
Branch: branch4

commit description:v3.14-4-example14-4 (application scenario (VII) - improve the paging function to jump to a page and solve the error reporting problem)

tag: v3.14-4

However, this method is highly recommended. If it is modified in the later stage, a component is nested in the home component, then b component is nested in the a component, and then b component is nested in the paging component. In this way, you need to transfer it layer by layer, and the logic will be very cumbersome.

At this time, we can rely on the withRouter component (high-level component) to solve this problem.

2.3.7.2.5 example14-5

Package Pagination through withRouter. Several objects related to routing will be injected into props of Pagination component inside withRouter, and Pagination will be returned

Higher order components - higher order functions

react-Novice05\app\src\components\Pagination.js

import {Link, withRouter} from 'react-router-dom';
......
export default withRouter(Pagination);

react-Novice05\app\src\views\Home.js

                <div>
                    <Pagination page={page} pages={10} />
                </div>

commit description:v3.14-5-example14-5 (application scenario (VII) - improve the paging function of jumping to a page, complete)

tag: v3.14-5

We can search for high-level components (HOC) on the react official website

High order components are functions whose parameters are components and return values are new components. That is, when a component is passed in, a component comes out.

However, compared with the original components, the new components have been expanded through high-order functions.

Scroll down to see the source code:

// This function receives a component
function withSubscription(WrappedComponent, selectData) {
  // And And return to another component
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }
 
    componentDidMount() {
      // And Responsible for subscription related operations
      DataSource.addChangeListener(this.handleChange);
    }
 
    componentWillUnmount() {
      DataSource.removeChangeListener(this.handleChange);
    }
 
    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }
 
    render() {
      // And And render the wrapped components with the new data!
      // Note that we may also pass other attributes
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

Mainly looking at the return value, this is actually equivalent to introducing This Props, just like we introduced props ourselves at the beginning.

The foundation of react is almost complete, and the rest will be expanded by Xiaodi in the future.



(to be supplemented later)

Tags: Vue Web Development React

Posted by ali_2kool2002 on Mon, 30 May 2022 16:37:59 +0530