“This is the 8th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”

React

The life cycle

  • Mount unmount process
    • 1.1. The constructor ()
    • 1.2.com ponentWillMount ()
    • 1.3.com ponentDidMount ()
    • 1.4.com ponentWillUnmount ()
  • The update process
    • 2.1. componentWillReceiveProps (nextProps)
    • 2.2. ShouldComponentUpdate (nextProps nextState)
    • 2.3.com ponentWillUpdate (nextProps nextState)
    • 2.4.com ponentDidUpdate (prevProps prevState)
    • 2.5 render ()
  • React new lifecycle (personal supplement)
    • 3.1. getDerivedStateFromProps(nextProps, prevState)
    • 3.2. getSnapshotBeforeUpdate(prevProps, prevState)

The React lifecycle is broadly divided into three phases: mount, render, and unload

Therefore, the React lifecycle can be divided into two types: mount and unload processes and update processes. React lifecycle diagram:

1. Mount and uninstall process

1.1. The constructor ()

The React data is initialized by constructor(), which accepts two parameters: props and context. When you want to use these two parameters inside a function, you need to pass them in with super(). Note: Whenever you use constructor() you must write super(), otherwise this will point to an error.

1.2.com ponentWillMount ()

ComponentWillMount () is used less often, and more often for server-side rendering. It represents the process when the component has gone through a constructor() initialization of data, but has not yet rendered the DOM.

1.3.com ponentDidMount ()

When the component is rendered for the first time and the DOM node has been generated, an Ajax request can be called from here and the component will be rendered again after the setState data is returned

1.4.com ponentWillUnmount ()

This is where component uninstallation and data destruction are completed.

  1. Clear all setTimeout,setInterval in your build
  2. Remove removeEventListener from all builds
  3. Sometimes we get this warning:
Can only update a mounted or mounting component. This usually      means you called setState() on an unmounted component. This is a   no-op. Please check the code for the undefined component.
Copy the code

Cause: Your ajax request in the component returns setState, and when the component is destroyed, the request is not complete, so it will report warning:

componentDidMount() {
    this.isMount === true
    axios.post().then((res) => {
    this.isMount && this.setState({   // Add condition ismount to true
      aaa:res
    })
})
}
componentWillUnmount() {
    this.isMount === false
}
Copy the code

2. Update process

2.1. componentWillReceiveProps (nextProps)

  1. This is often used when props need to re-render the component after accepting changes to the parent component
  2. Accept a parameter, nextProps
  3. The component is rerendered by comparing the state of nextProps to the state of the current component
componentWillReceiveProps (nextProps) { nextProps.openNotice ! = =this.props.openNotice&&thisSetState ({openNotice: nextProps openNotice}, () = > {the console. The log (this.state.openNotice:nextProps)
      // Update state to nextProps. The new state can be printed on the second parameter (callback) of setState})}Copy the code

2.2. ShouldComponentUpdate (nextProps nextState)

  1. Mainly used for performance optimization (partial update)
  2. The only way to control the life cycle of a component’s re-rendering is to setState in react and the component will enter the re-rendering process. Return false prevents the component from updating
  3. Rerendering of the React parent will result in rerendering of all of its children. In this case, we do not need to re-render all of the children, so we need to make decisions in the life cycle of the children

2.3.com ponentWillUpdate (nextProps nextState)

ShouldComponentUpdate returns true, the component goes to the rendering process, and goes to componentWillUpdate, where we can also get nextProps and nextState.

2.4.com ponentDidUpdate (prevProps prevState)

React will only enter componentDidmount when it is initialized for the first time, and will enter the life cycle after every re-rendering. PrevProps and prevState are the props and prevState before the update.

2.5 render ()

The Render function inserts the DOM structure generated by JSX. React generates a virtual DOM tree. At each component update, React uses its diff algorithm to compare the old and new DOM trees before and after the update, find the smallest dom nodes that differ, and re-render them.

3. React Added lifecycle (Personal supplement)

React Added life cycle

3.1. getDerivedStateFromProps(nextProps, prevState)

Instead of componentWillReceiveProps (). The old version componentWillReceiveProps () method before and after judgment two props are the same, if different then the new props to update to the corresponding state. Doing so breaks the single source of state data, making the state of the component unpredictable and, on the other hand, increasing the number of component redraws. Here’s an example:

// before
componentWillReceiveProps(nextProps) {
  if(nextProps.isLogin ! = =this.props.isLogin) {
    this.setState({ 
      isLogin: nextProps.isLogin,   
    });
  }
  if (nextProps.isLogin) {
    this.handleClose(); }}// after
static getDerivedStateFromProps(nextProps, prevState) {
  if(nextProps.isLogin ! == prevState.isLogin) {return {
      isLogin: nextProps.isLogin,
    };
  }
  return null;
}

componentDidUpdate(prevProps, prevState) {
  if(! prevState.isLogin &&this.props.isLogin) {
    this.handleClose(); }}Copy the code

The two biggest difference is: in componentWillReceiveProps, we usually do the following two things: one is based on the props to update the state, the second is to trigger some correction, such as animation or page jump.

  1. In the old version of the React, these two things we all need to do in the componentWillReceiveProps.
  2. In the new version, the update state and trigger callback are reassigned to getDerivedStateFromProps and componentDidUpdate, making the overall update logic of the component clearer. Also, getDerivedStateFromProps disallows the component from accessing this. Props, forcing the developer to compare the values of nextProps and prevState. To make sure that when developers use the getDerivedStateFromProps lifecycle function, they are updating the component’s state based on the current props, rather than doing something else that makes the component’s state more unpredictable.

3.2. getSnapshotBeforeUpdate(prevProps, prevState)

ComponentWillUpdate instead. A common use case for componentWillUpdate is to read the current state of a DOM element and process it in componentDidUpdate before the component is updated. The difference between the two is:

  1. When asynchronous render mode is enabled in React, the DOM element states read in render are not always the same as those read in commit. This makes it unsafe to use the DOM element states read in componentWillUpdate in componentDidUpdate because the values are likely to be invalid.
  2. GetSnapshotBeforeUpdate is called before final render, which means that the DOM element states read in getSnapshotBeforeUpdate are guaranteed to be the same as in componentDidUpdate. Any values returned by this life cycle are passed as arguments to componentDidUpdate ().

JSX profile

What is JSX??

Looking back at the code above,

Hello World!

Isn’t that weird? How can THERE be HTML tags in JS? !

Yes, JS can write HTML tags, this form, is JSX.

JSX is neither a string nor HTML. It is a syntax for writing HTML tags in JS.

You can also assign it this way. const element =

Hello World!

In JSX, you can also declare variables or introduce expressions with {}. You can put any JS expression in {}.

Such as

Hello, Zhang {1 + 2}

Or we could say const name = ‘zhang SAN’

hello {name}

Note: the JSX class attribute should be written as className.

After reading this, YOU must still be confused about JSX.

But don’t worry, there will be a lot of JSX in the future, and if you use more, you will definitely love it!

component

Component, similar to JS functions. However, the function name of the component should be capitalized. (Lowercase is function, uppercase is component)

A component is a separate piece of code. Call render directly when needed.

Component, which is written in two standard ways:

First, of functional form, for example:

function Welcome() { return ( <h1>Hello world! </h1> ) } ReactDOM.render( <Welcome />, document.getElementById('root') )Copy the code

Second, of the class form, e.g.

class Welcome extends React.Component { render() { return ( <h1>Hello World! </h1> ) } } ReactDOM.render( <Welcome />, document.getElementById('root') )Copy the code

So these two ways of writing it are equivalent.

So these two ways of writing it are equivalent.

Two examples, two standard formats. That is, it doesn’t matter what form you use or what content you render.

Composition versus inheritance

Official documentation: clever use of combination, careful use of inheritance

Composition is very easy to use in the actual coding process, and we have used it many times in the process of learning.

For example:

function App1() { return ( <h1>Hello, React! </h1>)} function App2() {return (<h1> react! } function App3() {return (<div> <App1 /> <h3> </h3> <App2 /> </div> ) } ReactDOM.render( <App3 />, document.getElementById('root') )Copy the code

/ / the case was put through App3 component App1 and App2 together, through the render renders. Output result:

Hello, React! Hello react!Copy the code

The CSS class name

Use className instead of className. React JSX uses className instead of className.

`Warning: Invalid DOM property `class`. Did you mean `className`?
Copy the code
<input className="input" />
Copy the code

Conditions apply colours to a drawing

import React, {Component} from 'react'

class Condition extends Component {
  constructor(props) {
    super(props)
    this.state = {
      show: false.list: [{id: 1.age: 11},
        {id: 2.age: 22},
        {id: 3.age: 33}}},]render() {
    // If else render
    if(this.state.show) {
      return <p>hello</p>
    }else {
      return <p>byebye</p>
    }

    // A ternary expression
    // return (this.state.show ? <p>hello</p> : <p>byebye</p>)

    / / and operation &&, or operational | |
    // return this.state.show && <p>hello</p>
    // return this.state.show || <p>byebye</p>}}export default Condition
Copy the code

suspense

Suspense usually works with asynchronous components to add wait animations or other actions when asynchronous components are not loading

import React,{ Component, Suspense } from 'react';
const AsyncComp = React.lazy(() = > import('./FormInput'))
class SuspenseDemo extends Component {
  render() {
      // fallback represents the display effect before the asynchronous operation
     return <Suspense fallback={<div>Loading...</div>}> {/* Here is the component introduced asynchronously */}<AsyncComp/>
      </Suspense>}}export default SuspenseDemo;
Copy the code

Render loop

For map rendering, the key is the same as vUE, and index or random is generally not set

    // Loop render
    return (
      <ul>
        {this.state.list.map(item => 
          {
            return <li key={item.id}>{item.age}</li>})}</ul>
    )
Copy the code

State of the state

  • usethis.stateDefine the state to usethis.setState({xxx: xxx})Mode To modify the status
  • stateThe data cannot be used directlythis.state.xxx = xxxForm to change the state becausereacttheimmutableIt’s conceptually determined. It specifiesstateThe data cannot be changed directly in thesetStateMode modification, must bestateMake a copy of your data for modification
import React, { Component } from 'react'

class SetStateDemo extends Component{
  constructor(props) {
    super(props)
    this.state = {
      count: 0.list: [{id: 1.age: 1},
        {id: 2.age: 2}
      ]
    }
  }
  addCount = () = > {
    // It is recommended to use this method to copy the original data and modify it
    const newList = this.state.list.slice()
    newList.push(3)
    this.setState({
      // if this.state.count++ is used, a warning will be issued because this line directly changes the value of the original count:
      // Do not mutate state directly. Use setState()
      // count: this.state.count++
      count: this.state.count + 1.list: newList
    })
    console.log(this.state.count) // This is asynchronous
  }
  render() {
    return (
      <div>
        <p>{this.state.count}</p>
        <button onClick={this.addCount}>cumulative</button>
      </div>)}}export default SetStateDemo;
Copy the code

The event

  • Event to useon + Capital humpFor exampleonClink={this.xxx}Is the same asThe vue @ click = "XXX"
  • event-relatedthisTo:
    1. The first way:
      • useES5Way to define events,thisWill default toundefined, in order to usebindTo bindthisPoint, or an error will be reportedCannot read property 'setState' of undefined
      • The eventbind(this)Written in the bestconstructor, this will only be executed oncebindAnd cache the results, if written on the label, click once to executebind, and when used in more than one place, more than one placebind, so write inconstructorIs a performance optimization
    2. The second way to write it is to useES6Arrow function,thisWill default to the current instance, do not need to worry aboutthisPoint to, but may need tobabelTo translate
import React, { Component } from 'react'

class Event extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'flower',}// The first way is to bind this to the event
    this.handleClick = this.handleClick.bind(this)}render() {
    // When clicked multiple times, bind will be triggered multiple times
    // Bind only once from constructor, saving cached results as a performance optimization
    // return <p onClick={this.handleClick.bind(this)}>{this.state.name}</p>

    // Bind events using the onXxxx notation
    
    return (
      <div>{/* the first way */}<p onClick={this.handleClick}>{this.state.name}</p>{/* Second way */}<p onClick={this.handleClick2}>{this.state.name}</p>
      </div>)}// The first definition method
  handleClick() {
    // Modify data with setState
    this.setState({
      name: 'small'})}// The second way to define a method is to use the arrow function so that this points to the current instance
  handleClick2 = (event) = > {
    console.log(event);
    // Modify data with setState
    this.setState({
      name: 'small'}}})export default Event
Copy the code
  • Nature of the event
    1. inreactIn the useeventGets the current event, but sees that the print isSyntheticBaseEvent, this isreactSynthetic events are not nativeMouse EventIt simulates all the capabilities of DOM events, including bubbling, blocking events, and so on
    2. Can be achieved byevent.nativeEventGet native events
    3. All the events in thereact16Before, they were all mounted todocumentOn; inreact17After, it will be mounted torootOn the root element, this favors multipleReactVersion coexistence, such as micro front-end; Can be achieved byevent.navtiveEvent.currentTargetTo get the mount element
    4. This anddomThe events are different, andvueThe events were different,vueThe event is nativeMouse EventAnd will be mounted to the current element
render() {    
    return (
      <div>{/* react event properties */}<a href="http://www.baidu111.com" onClick={this.handleClick3}>Skip links</a>
      </div>)}Copy the code
  // React
  handleClick3 = (event) = > {
    console.log('handleClick3');
    // SyntheticBaseEvent is a synthetic Event handled by React itself, not a native Mouse Event
    // This is different from vue, where events are native and are mounted to the current element via $event
    console.log(event)
    event.preventDefault()  // Block native operations, such as a TAB jump, right chain menu, etc
    event.stopPropagation() // Prevent bubbling

    // Get the native event MouseEvent
    console.log('event nativeEvent:', event.nativeEvent); 

    // Native event object,  jump link 
    console.log('nativeEvent target:', event.nativeEvent.target)  

    // The object that was mounted to document before React16 and root after react17
    console.log('nativeEvent currentTarget:', event.nativeEvent.currentTarget ) 
  }
Copy the code

image.png

  • Parameter passing to the event
  1. usebindThe custom parameter is passed from the second
<p onClick={this.handleClick4.bind(this, 'aa', 'bb')} >Event reporter I</p>
Copy the code
// Event is added to the last parameter by default
  handleClick4(a, b, event) {
    console.log('parameters:, a, b, event);  // Parameter: aa bb SyntheticBaseEvent
  }
Copy the code
  1. Using the arrow function,eventNeed to be defined in the returned function
<p onClick={this.handleClick5('aa')} >Event parameter 2 was transmitted</p>
Copy the code
// We need to return a function with event as an argument
  handleClick5 = (a) = > {
    return (event) = > {
      console.log('a', a);  // aa
      console.log('e', event);  // SyntheticBaseEvent}}Copy the code
  1. When binding, use the arrow function that willeventParameter passing, recommended to use this method, the writing method is convenient and concise
<p onClick={(e)= >This.handleclick6 ('aa', e)}> EventPass parameter 3</p>
Copy the code
  // There is no need to return a function
  handleClick6 = (a, event) = > {
    console.log(a);
    console.log(event)
  }
Copy the code

The controlled components

A controlled component, as its name suggests, means that the state of the component is controlled by React. Vue uses the V-Model to bind forms in both directions. React does not provide a similar API, so you need to implement it:

  • forinput,textarea,selectAnd so on are controlledvalueValue to control the form content, throughonChangeTo listen for form input
  • forradio,checkboxAnd so on through controlcheckedValue to control the form content, throughonChangeTo listen for form input
import React, { Component } from 'react';

class FormInput extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'flower'.info: 'xxxx'.city: 'shenzhen'.flag: true.gender: 'female'.like: ['basketball']}}render() {
    let  { name, info, city, gender, like } = this.state
    // Form controlled components
    return  <div>
        <p>{name}</p>
        <label htmlFor="inputName">Name:</label>
        <input type="text" id="inputName" value={name} onChange={this.inputChange}/>
        <hr/>
        <p>Personal Information:<span>{info}</span></p>
        <textarea value={info} onChange={this.textareaChange}></textarea>
        <hr/>
        <p>City:<span>{city}</span></p>
        <select value={city} onChange={this.selectChange}>
          <option value="beijing">Beijing</option>
          <option value="shenzhen">shenzhen</option>
          <option value="shangehai">Shanghai</option>
        </select>
        <hr/>
        <p>Gender:<span>{gender}</span></p><input type="radio" name="gender" value="male" checked={gender= = ='male'} onChange={this.radioChange}/><input type="radio" name="gender" value="female" checked={gender= = ='female'} onChange={this.radioChange}/>
        <hr/>
        <p>Likes: {like.map(item => {return<span>{item}</span> 
        })}</p>
        <input type="checkbox" value="basketball" checked={like.includes('basketball')} onChange={this.checkboxChange}/>basketball<input type="checkbox" value="football" checked={like.includes('football')} onChange={this.checkboxChange}/>football</div>
    
  }
  inputChange = (e) = > {
    this.setState({
      name: e.target.value
    })
  }
  textareaChange = (e) = > {
    this.setState({
      info: e.target.value
    })
  }
  selectChange = (e) = > {
    this.setState({
      city: e.target.value
    })
  }
  radioChange = (e) = > {
    this.setState({
      gender: e.target.value
    })
  }
  checkboxChange = (e) = > {
    const val = e.target.value
    let newLike = this.state.like.slice();
    if(this.state.like.indexOf(val) ! = = -1) {
      let index = this.state.like.indexOf(val)
      newLike.splice(index, 1)}else {
      newLike.push(val)
    }
    this.setState({
      like: newLike
    })
  }
}

export default FormInput
Copy the code

Communication between parent and child components

Similar to VUE, but the parent component methods and properties are passed through properties (unlike Vue, where events are passed through V-ON /@), the child component does not emit the parent component methods, but this. Props. ParentMethod

/ / the parent component

  render() {
    return (
       <TodoItem 
          content={item} 
          index={index} 
          deleteItem={this.handleDelete.bind(this)}
        />
    )
  }
  handleDelete=(index) = >{
    // Immutable is a concept that does not allow you to modify data directly on state, otherwise later performance tuning may be problematic
    let list = [...this.state.list]   // Make a copy of it and make changes on it
    list.splice(index,1)
    this.setState({
      list: list
    })
  }
Copy the code
/ / child component
import React, { Component } from 'react'

class TodoItem extends Component {
  constructor(props) {
    super(props);
    // Point this to the current React component. Specify this in the constructor to optimize performance
    this.handleClick = this.handleClick.bind(this)}render() {
    return (
      // Before the optimization, we can write:
      //<div onClick={this.handleClick.bind(this)}></div>
      <div onClick={this.handleClick}></div>)}handleClick() {
    // Trigger the parent component method
    this.props.deleteItem(this.props.index)
  }
}
Copy the code

State of ascension

Often, multiple components need to reflect the same changing data, and we recommend promoting the shared state to the nearest common parent. This is called state elevation.

Personally, I feel that the cases given in the official documents are a little difficult to look at, so I wrote a length conversion case as follows:

Let dataTitle = {m: 'input m: ', cm: 'Input cm: LengthData extends React.Component {render() {let title = this.props this.props.input let onChange = this.props.onChange let data = this.props.data return ( <fieldset> <legend>{title}</legend> <input type="text" value={data} onChange={onChange} /> </fieldset>)}} // Write a component class that implements the input box {constructor(props) {super(props) // state = {type: '', input: '' } } checkedInput(input) { // console.log(typeof(input)) if (Number.isNaN(input) || parseFloat(input) < 0) { alert (' Incorrect input data, re-enter! ') this.setState({ type: '', input: '' }) } return input } convertCM(input) { return input * 100 } convertM(input) { return input / 100 } handleChange=(type, e) => { if (type === 'meter') { this.setState({ type: 'meter', input: e.target.value }) }else if (type === 'centimeter') { this.setState({ type: 'centimeter', input: E.targe.value})}} render() {// Meter rectification type data these are variables that are set up for interaction let input = this.state.input let type = this.state.type let meter = type === 'centimeter' ? this.convertM(this.checkedInput(input)) : input let centimeter = type === 'meter' ? this.convertCM(this.checkedInput(input)) : Input return (<div> <h3> </h3> <LengthData title={datatitle. m} data={meter} onChange={(e)=> {this.handleChange('meter' ,e)}} /> <LengthData title={dataTitle.cm} data={centimeter} onChange={(e)=> {this.handleChange('centimeter' ,e)}} /> </div> ) } } ReactDOM.render( <Length />, document.getElementById('root') )Copy the code

** Step 1: ** Write the component that implements the input box (this step is not obvious in the code case)

** Step 2: ** Extract input box components (easy to write multiple input boxes)

** Step 3: ** State promotion (remove the state from the child component and put the state in the parent component)

** Step 4: ** State interaction (core code, also the most difficult code to understand)

** Step 5: ** Debug bugs (debug input and output results, such as input does not meet requirements, give error messages, and then empty the input field to prevent interaction)

react-redux

1. What is redux

Official explanation: Redux is a container of predictable state for JS applications. Can be understood as a global data state management tool (state manager), used to do component communication, etc.

2、为什么使用redux

When redux is not used, passing values between sibling components is cumbersome and the code is complex and redundant. Using Redux to define a global single data Store, you can customize what data is stored in the Store, and the entire data structure is also clear.

3, the state

State in the front end is data, it’s an object. State in redux cannot be changed directly, only through action, which is equivalent to defining setter methods in a singleton.

4, the action

Redux describes each change as an action, and to change the contents of state, you need to send the action. An action is a simple object that describes what has changed in state.

const INCREMENT = 'INCREMENT'
const incrementAction = {"type": INCREMENT, "count": 2}
Copy the code

This is an action, which is an object, based on the type of the action.

5, reducer

The data state indicates that the action is there so it’s implemented. Reducer is a reducer that controls state based on actions.

const calculate = (state: ReduxState = initData, action: Action ) => {
    switch (action.type) {
        case INCREMENT:
            return {num: state.num + action.count}
        case REDUCE:
            return {num: state.num - action.count}
        default:
            return state
    }
}

export {calculate}
Copy the code

A new state is returned after the reducer operation, such as adding or subtracting state.num based on the action type.

6, store

A store is where data is stored for the entire project, and there can only be one. Create a store and reducer everything into it.

import { createStore, combineReducers } from "redux";
import { calculate } from "./calculate";

You can create multiple reducers together here
const rootReducers = combineReducers({calculate})
// Manage a store globally
export const store = createStore(rootReducers)
Copy the code

7, dispatch

Store.dispatch () is the only way a component can issue an action.

store.dispatch(incrementAction);
Copy the code

By calling incrementAction from the store, the store data is modified directly.

8. Use of Redux

Article: www.jianshu.com/p/794f5aabb…

Video: www.bilibili.com/video/BV1d4…