“This is the third day of my participation in the Gwen Challenge.

preface

The life cycle of Vue components is divided into four stages: creation, mount, update and destruction. The respective hook functions will be triggered before and after each stage of the life cycle, such as:

  • Components are executed before they are createdbeforeCreateHook function;
  • After component creationcreatedHook function;
  • Components before mountingbeforeMountHook function;
  • After the component is mountedmountedHook function;
  • Component before updatebeforeUpdateHook function;
  • After component updateupdatedHook function;
  • Before component destructionbeforeDestroyHook function;
  • After component destructiondestroyedHook function.

The React component life cycle is divided into mount, update, and uninstall phases. The most important part of learning the life cycle is to know which hook functions are triggered in each phase of the life cycle. React provides the lifecycle Hook functions provided by React. However, this diagram shows the lifecycle Hook functions provided by React after Version 16.4 and can only be used in class components. The lifecycle Hook functions in function components are implemented by React Hook in future articles.

1. Mount the React component

During the React component mount phase, the hook functions constructor, getDerivedStateFromProps, componentDidMount, and Render are called in order.

import React from 'react'; class HelloWorld extends React.Component { constructor(props) { super(props); this.state = { title: 'hello React' }; Console. log(' perform constructor')} static getDerivedStateFromProps(props, State){console.log(' execute getDerivedStateFromProps') return null; } componentDidMount(){console.log(' componentDidMount')} render() {console.log(' componentDidMount') return ( <div>{this.state.title}</div> ); } } export default HelloWorld;Copy the code

After executing the above code, the console will print the following:

1.1 the constructor

Constructor is actually the constructor of a subclass of React.Com. There are three things we do.

  • Called before any other statementsuper(props), otherwise,this.propsforundefined;
  • Initialize state by assigning the this.state object;
  • Bind the instance to the event handler, otherwise it cannot be used in the functionthis.
import React from 'react';
class HelloWorld extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: 'hello React' };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log(this)
  }
  render() {
    return (
      <div onClick={handleClick}>{this.state.title}</div>
    );
  }
}
export default HelloWorld;

Copy the code

In addition, the following two points should be paid special attention:

  • You can’t usethis.setState()To initialize the internal state, as follows:
constructor(props) {
    super(props);
    this.setState({
      title:'hello world'
    })
}
Copy the code
  • You cannot assign props to state and then use state instead of props, because when the props is updated, the corresponding state is not updated.
constructor(props) {
    super(props);
    this.state({
      title:this.props.title
    })
}
Copy the code

1.2 getDerivedStateFromProps

This is an uncommon hook function that derives a new state from the component’s props. The getDerivedStateFromProps hook function takes props and state of the component as arguments and returns an object or null. If an object is returned, the object is used to update state. If null is returned, the state is not updated.

import React from 'react'; class HelloWorld extends React.Component { constructor(props: any) { super(props); this.state={ info:'hello world' }; } static getDerivedStateFromProps(props, state){ let stateName = props.state == 1? 'In process ':' completed '; return { stateName }; } render() { return ( <div>{this.state.stateName}</div> ); } } export default HelloWorld;Copy the code

There are three points to note when using the getDerivedStateFromProps hook function:

  • To derive new states, do not modify the original state;
  • The function must return an object or null at the end;
  • Cannot be used in the hook functionthis.

1.3 render

The render function should be pure and should not modify the state and props in it. When writing the React element with JSX, the React element is bound to data via state and props. Finally, some React elements must be returned, and these React elements must have only one root element. To avoid adding a useless tag to the DOM, use < react. Fragment> as the root element.

render() {
  <React.Fragment>
    <div>{this.state.title}</div>
    <div>{this.props.info}</div>
  </React.Fragment>
}
Copy the code

1.4 componentDidMount

The componentDidMount hook function is called immediately after the component is mounted, much like Vue’s Mounted hook function.

In which we can generally do the following operations

  • Get the DOM element;
  • Request server data;
  • Listen to events, must be incomponentWillUnmount()Cancel listening;
  • You can callthis.setState()To change the state data.
componentDidMount(){
  this.setState({
    title:'hello world'
  })
}
Copy the code

2. Update the React component

The React component update phase calls getDerivedStateFromProps, shouldComponentUpdate, Render, getSnapshotBeforeUpdate, and componentDidUpdate in sequence .

import React from 'react'; class HelloWorld extends React.Component { constructor(props: any) { super(props); this.state = { title: 'hello world' } this.update = this.update.bind(this); } static getDerivedStateFromProps(props, state) {console.log(' execute getDerivedStateFromProps');} static getDerivedStateFromProps(props, state) {console.log(' execute getDerivedStateFromProps'); return null; } shouldComponentUpdate(nextProps, nextState) {console.log(' shouldComponentUpdate'); return true; } getSnapshotBeforeUpdate(prevProps, prevState) {console.log(' execute getSnapshotBeforeUpdate'); return null; } componentDidUpdate() {console.log(' componentDidUpdate')} Update() {this.setState({title: 'Hello react'}} render() {console.log(' render') return (<div onClick={this.update}>{this.state.title}</div>)}}  export default HelloWorld;Copy the code

After executing the above code, the console will print the following:

There are three actions that cause component updates in React:

  • The props of the component changes.

  • To perform this. SetState ();

    This.setstate (updater, [callback]) where undater can be an object or a function (state, props) => stateChange, where stateChange returns an object, This object is merged with this.state inside React to update the state. In addition, you can obtain the latest state and props of the component by using the function parameters state and props.

    Executing this.setstate () does not always update components immediately; it postpones updates in batches. This makes it a hazard to read this.state immediately after calling this.setstate (). So the second argument to this.setState, callback, is the optional callback function that reads the updated state.

    handleClick(){
      this.setState((state,props) =>{
        const count= state.count + 1;
        return {
          count,
        }
      },() =>{
        console.log(this.state.count)
      })
    }
    Copy the code
  • To perform this. ForceUpdate ().

    This.forceupdate () forces the component to re-render, similar to the vm.$forceUpdate() in Vue.

    handleClick(){
      this.forceUpdate();
    }
    Copy the code

    Executing this.forceUpdate() to cause component updates skips the shouldComponentUpdate hook function. But its children fire the normal lifecycle hook functions, including the shouldComponentUpdate hook function.

2.1 getDerivedStateFromProps

The getDerivedStateFromProps hook function is called during the component mount phase and is called during the component update phase, and the function receives updated state and props.

So the derived state is completely controlled by props, even if it is changed with this.setstate ().

2.2 shouldComponentUpdate

ShouldComponentUpdate hook function to receive the updated state and props, through the comparison, and update the state and props to determine whether to update components, finally, returns true if the function is updated components, otherwise returns false does not update the components, are used for performance optimization.

shouldComponentUpdate(nextProps, nextState) { if (this.props.color ! == nextProps.color) { return true; } if (this.state.count ! == nextState.count) { return true; } return false; }Copy the code

The following points should be noted when using the shouldComponentUpdate hook function:

  • If this.forceUpdate() is invoked in a component to trigger a component update, the hook function is not executed;

  • This.setstate () must be executed in a conditional statement, or it will fall into an infinite update loop, causing the program to crash.

  • The function must finally return true or false. If false is returned, the subsequent render, getSnapshotBeforeUpdate, and componentDidUpdate hook functions are not called.

2.3 render

Execute Render () to re-render the component.

2.4 getSnapshotBeforeUpdate

The getSnapshotBeforeUpdate hook function is equivalent to the beforeUpdate hook function in Vue.

When the getSnapshotBeforeUpdate hook function is called, the props and state are updated. Therefore, the hook function accepts the props and state before the update as parameters for comparison.

The getSnapshotBeforeUpdate hook function finally returns a value that is received by snapshot, the third parameter to the componentDidUpdate hook function.

The getSnapshotBeforeUpdate hook function is called before the component is rerendered and mounted to the DOM. Therefore, the DOM obtained in this hook function is still the updated DOM. Generally, the interaction operation before and after the component UI is updated is used.

For example, in the following example, the isOpen prop controls the display and hiding of a list, and the height of the list is adaptive. When an isOpen change causes a component to update, the pre-hidden list height can be obtained in the getSnapshotBeforeUpdate hook function for UI interaction.

import React from 'react'; class List extends React.Component { constructor(props) { super(props); this.listRef = React.createRef(); } getSnapshotBeforeUpdate(prevProps, prevState) { console.log(prevProps) if (prevProps.isOpen) { const listEl = this.listRef.current; return listEl.height; } return null; } componentDidUpdate(prevProps, prevState, snapshot) { console.log(snapshot) } render() { return ( <div> {this.props.isOpen && <div ref={this.listRef} > {/* ... contents... */} </div>} </div> ); } } export default List;Copy the code

There are three points to note when using the getSnapshotBeforeUpdate hook function:

  • This.forceupdate () or this.setState() must be executed in a conditional statement, or it will fall into an infinite update loop, causing the program to crash;

  • The function must return a value or NULL at the end, otherwise the code will report an error;

  • Must be called with the componentDidUpdate hook function, otherwise the code will report an error.

2.5 componentDidUpdate

The componentDidUpdate hook function is executed after the component has been rerendered and mounted into the DOM. The function parameters receive the state and props before the update, and the getSnapshotBeforeUpdate hook function returns the value with the Snapshot parameter.

componentDidUpdate(prevProps, prevState, snapshot){
  //...
}
Copy the code

There are two things to note when using the componentDidUpdate hook function:

  • This.forceupdate () or this.setState() must be executed in a conditional statement, or it will fall into an infinite update loop, causing the program to crash;

  • If the shouldComponentUpdate hook function returns false, the componentDidUpdate hook function is not called.

3. Uninstall the React component

3.1 componentWillUnmount

ComponentWillUnmount is called before the component is unmounted and destroyed. We generally deal with the following matters:

  • Clear timer;
  • Cancel the network request;
  • Solution is tied to thecomponentDidMountThe event that the hook function listens for.
componentWillUnmount(){
  //...
}
Copy the code

4. Mount the React parent component

In the React parent mount phase, the parent component’s Render function is called; the parent component’s constructor function is called; the parent component’s componentDidMount hook function is not called until the parent component’s Render function is called.

Constructor () {render () {componentDidMount () {render () {constructor () {render () {componentDidMount ();}} The parent component’s componentDidMount hook function is called last.

The parent component’s componentDidMount hook is not called until the last component’s componentDidMount hook is called.

React Parent component update phase

React updates work recursively from the top down, and no matter how many layers of components you have nested, updates to the last layer of components are triggered.

Vue updates only to the current component, and does not trigger the update of the child component, because the props of the child component has changed.

The React parent component updates, causing the child component’s hook function to be called in the update phase, as shown below:

When the parent component updates, after the render function is called, the getDerivedStateFromProps hook function of the child component is called until the getSnapshotBeforeUpdate hook function of the child component is called. The getSnapshotBeforeUpdate hook function of the parent component is called, then the child component’s componentDidUpdate hook function is called, and the parent component’s componentDidUpdate hook function is called.

Call the getSnapshotBeforeUpdate hook function of the child component, and then call the getSnapshotBeforeUpdate hook function of the child component. The component’s componentDidUpdate hook function is called only when the parent component’s getSnapshotBeforeUpdate hook function is called.

6. React Parent component uninstallation stage

After the React parent component is uninstalled. The deepest nested component first calls the componentWillUnmount hook function, then calls the componentWillUnmount constructor for each component in turn.

+

7. Optimize React component updates

React parent components are updated, regardless of whether the components’ state and props are changed. When you are used to Vue development, it is very strange that the props passed to the child components change, so the child components update. React updates can cause performance problems. Use the React.PureComponent to optimize performance by creating child components that are computatively expensive to update.

PureComponent creates a component that calls the shouldComponentUpdate hook function, so it cannot call the shouldComponentUpdate hook function again in this component.

ShouldComponentUpdate automatically compares props and state in the shouldComponentUpdate hook function, and returns true if the data changes to trigger the component update.

Note that this is only a superficial comparison between props and state. Here is an example to visually explain what a superficial comparison is.

import React from 'react'; class HelloWorld extends React.PureComponent { constructor(props: any) { super(props); } componentDidUpdate() {console.log(' componentDidUpdate')} render() {const {title, arr, obj} = this.props; return ( <div> <div>{title}</div> {arr.map((item,index) =>{ return ( <span key={index}>{item}</span> ) })} <div>{obj.a}</div> </div> ) } } export default HelloWorld;Copy the code
import React from 'react'; import HelloWorld from './HelloWorld'; class Index extends React.Component { constructor(props: any) { super(props); State = {title: 'Hello world', arr:[1,2,3], obj:{a:1}} this.handleclick = this.handleclick.bind (this); } handleClick() { let {arr,obj} = this.state; arr.push(4); obj.a =4; this.setState({ arr, obj, }) } render() { return ( <div onClick={this.handleClick}> <HelloWorld title={this.state.title} arr={this.state.arr} obj={this.state.obj}></HelloWorld> </div> ) } } export default Index; export default HelloWorld;Copy the code

“Shallow comparison” : compare only one layer of the properties of this.props, for example, if the properties are arrays or objects, without comparing nested data inside.

In other words, the value of an attribute is considered unchanged as long as its reference address does not change. Arrays and objects are reference types.

In the example above, adding a 4 to this.state.arr and changing the value of this.state.obj. A to 4 will not trigger the update of the child component.

To trigger an update to a component, assign a new array or object to this.state.arr or this.state.obj, which changes its reference address.

In the parent component, the update of the child component is triggered only when the props passed to the child component changes after a superficial comparison. This prevents the child component from being forced to update when the parent component’s data changes, thus optimizing the performance of the child component.

ForceUpdate can also be called to force child component updates.

import React from 'react';
import HelloWorld from './HelloWorld';
export default class Index extends React.Component {
  constructor(props) {
    super(props);
    this.myCom = React.createRef();
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.myCom.current.forceUpdate();
  }
  render() {
    return (
      <div onClick={this.handleClick} >
        <HelloWorld ref={this.myCom}></HelloWorld>
      </div>
    )
  }
}
Copy the code