Introduction to the

React has made some incremental changes to the lifecycle hook function since v16.3. Some lifecycle hook functions have been deprecated and some have been added.

  1. Comparison of old and new lifecycle functions
  2. Why should the old hook function be discarded
  3. Explain the new lifecycle usage scenarios
  4. Example code is demonstrated and summarized

Comparison of old and new life cycles

A complete React component lifecycle calls the following hooks in sequence:

old lifecycle

mount

  • constructor
  • componentWillMount
  • render
  • componentDidMount

update

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

uninstall

  • componentWillUnmount

new lifecycle

  • mount
    • constructor
    • getDerivedStateFromProps
    • render
    • componentDidMount
  • update
    • getDerivedStateFromProps
    • shouldComponentUpdate
    • render
    • getSnapshotBeforeUpdate
    • componentDidUpdate
  • uninstall
    • componentWillUnmount

From the above the life cycle of contrast, we see not hard, the React since v16.3 abandoned componentWillMount componentWillReceiveProps componentWillUpdate three hooks

Analysis of abandonment causes

It took Facebook more than two years to get React Fiber out of the way, because in v15 updates were synchronous and one main thread was often tied up for long periods of time, causing page performance issues

React Fiber uses the browser requestIdleCallback to fragment interruptible tasks, with each piece running for a short time so that a single thread is not monopoled

For more information, please click the following link: Morgan Zhihu

How does React Fiber affect the life cycle?

The React Fiber Reconciliation process may pause and continue, so the lifecycle hooks before mounting and updating may not execute or execute multiple times;

React currently provides aliases for these lifecycle hooks:

  • UNSAFE_componentWillMount
  • UNSAFE_componentWillReceiveProps
  • UNSAFE_componentWillUpdate

Act17 will only provide aliases, with individual names designed to disgust you from using them.

Explain the new life cycle

Life cycle function of each phase

constructor()

Constructor () is called before the React component is mounted. When implementing the constructor for the react.componentsubclass, super() should be called before any other statement.

Super inherits this object from the parent class to subclasses (MDN reference)

In general, the React constructor is only used in two cases:

  • To initialize the internal state of the function
  • Bind the instance to the event handler function

If state is not initialized or method binding is not performed, nothing needs to be written constructor() and just set this.state

You cannot call this.setstate () inside the constructor() function because the first render() has not yet been executed, which means the DOM node has not yet been mounted

static getDerivedStateFromProps(nextProps, prevState)

GetDerivedStateFromProps () is called before the Render method is called, and is called during initialization and subsequent updates

Return value: An object is returned to update state. If null is returned, nothing is updated

Parameters: The first parameter is props to be updated, and the second parameter is state of the previous state. You can compare props and state to add some restrictions to prevent useless state updates

Note: getDerivedStateFromProps is a static function. You can’t use this, which means you can only do things that have no side effects

As for why? Please move on to Big Morgan. – Zhihu

render()

The render() method is the only one that must be implemented in the class component to render the DOM, and the Render () method must return the reactDOM

Note: do not setState in render, otherwise it will trigger an infinite loop and crash memory

componentDidMount()

ComponentDidMount () is called immediately after the component is mounted. ComponentDidMount () is a good time to send a network request, enable event listening methods, and call setState() directly from the hook function.

shouldComponentUpdate(nextProps, nextState)

ShouldComponentUpdate () is called before component update and controls whether or not the component is updated. Return true if the component is updated and false if the component is not updated

Contains two parameters. The first parameter is the props value to be updated, and the second parameter is the state value to be updated. You can compare the props or state value before and after the update and add some restrictions to determine whether to update and optimize performance

Deep comparisons or using json.stringify () in shouldComponentUpdate() are not recommended. This is very inefficient and can hurt performance

Do not call setState() in shouldComponentUpdate as this will cause an infinite loop of updates and renders until the browser memory crashes

Use the built-in PureComponent component instead

getSnapshotBeforeUpdate(prevProps, prevState)

GetSnapshotBeforeUpdate () is called before the last render output is committed. That is, after render, when the component is about to be mounted.

It allows the component to capture some information (such as scroll position) before the DOM is actually updated, and any values returned by this lifecycle are passed as arguments to componentDidUpdate(). If no value needs to be passed, return NULL

componentDidUpdate(prevProps, prevState, snapshot)

ComponentDidUpdate () is called immediately after the update. The first render will not be executed

Contains three parameters, the first of which is the previous props value. The second is the last state value. The third is the “snapshot” parameter passing if the component implements the getSnapshotBeforeUpdate() life cycle (not often)

SetState () can be used to compare the props before and after conditional statements, otherwise it will cause an infinite loop

componentWillUnmount()

ComponentWillUnmount () is called when a component is about to be unmounted or destroyed.

This life cycle is a good time to cancel network requests, remove listening events, clean up DOM elements, clean up timers, and so on

Life cycle execution order

When creating

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

update

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

When unloading

  • componentWillUnmount()

Examples show

The react version of the following code is 16.4.0, which changes the parent component props. The parent component unloads and remounts the child component, and the child component changes its state. The execution sequence of its lifecycle is explained

Component code presentation

Parent component: parent-js
import React, { Component } from 'react';
import { Button } from 'antd';
import Child from './child';

const parentStyle = {
  padding: 40.margin: 20.backgroundColor: 'LightCyan'};const NAME = 'Parent component: ';

export default class Parent extends Component {
  constructor() {
    super(a);console.log(NAME, 'constructor');
    this.state = {
      count: 0.mountChild: true}; }static getDerivedStateFromProps(nextProps, prevState) {
    console.log(NAME, 'getDerivedStateFromProps');
    return null;
  }

  componentDidMount() {
    console.log(NAME, 'componentDidMount');
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log(NAME, 'shouldComponentUpdate');
    return true;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log(NAME, 'getSnapshotBeforeUpdate');
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log(NAME, 'componentDidUpdate');
  }

  componentWillUnmount() {
    console.log(NAME, 'componentWillUnmount');
  }

  /** * Modifies the method passed to the child component property count */
  changeNum = () = > {
    let { count } = this.state;
    this.setState({
      count: ++count,
    });
  };

  /** * Toggle the methods of mounting and unmounting child components */
  toggleMountChild = () = > {
    const { mountChild } = this.state;
    this.setState({
      mountChild: !mountChild,
    });
  };

  render() {
    console.log(NAME, 'render');
    const { count, mountChild } = this.state;
    return (
      <div style={parentStyle}>
        <div>
          <h3>The parent component</h3>
          <Button onClick={this.changeNum}>Change the attribute count passed to the child component</Button>
          <br />
          <br />
          <Button onClick={this.toggleMountChild}>Unmount/mount child components</Button>
        </div>
        {mountChild ? <Child count={count} /> : null}
      </div>); }}Copy the code
Child component: child.js
import React, { Component } from 'react';
import { Button } from 'antd';

const childStyle = {
  padding: 20.margin: 20.backgroundColor: 'LightSkyBlue'};const NAME = 'Child component: ';

export default class Child extends Component {
  constructor() {
    super(a);console.log(NAME, 'constructor');
    this.state = {
      counter: 0}; }static getDerivedStateFromProps(nextProps, prevState) {
    console.log(NAME, 'getDerivedStateFromProps');
    return null;
  }

  componentDidMount() {
    console.log(NAME, 'componentDidMount');
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log(NAME, 'shouldComponentUpdate');
    return true;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log(NAME, 'getSnapshotBeforeUpdate');
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log(NAME, 'componentDidUpdate');
  }

  componentWillUnmount() {
    console.log(NAME, 'componentWillUnmount');
  }

  changeCounter = () = > {
    let { counter } = this.state;
    this.setState({
      counter: ++counter,
    });
  };

  render() {
    console.log(NAME, 'render');
    const { count } = this.props;
    const { counter } = this.state;
    return (
      <div style={childStyle}>
        <h3>Child components</h3>
        <p>Count: {count}</p>
        <p>Subcomponent state counter: {counter}</p>
        <Button onClick={this.changeCounter}>Change its state counter</Button>
      </div>); }}Copy the code

The interface display

Explore the execution order of the lifecycle in terms of when five component states change

Initialize the parent and child components

When the parent component is first rendered to load:

The printing order of the console is:

  • Parent component: constructor()
  • Parent component: getDerivedStateFromProps()
  • Parent component: render()
  • Child component: constructor()
  • Child component: getDerivedStateFromProps()
  • Child component: render()
  • Child component: componentDidMount()
  • Parent component: componentDidMount()
The child component modifies its state state

Click the button of subcomponent [change its own state counter], its value of [own state counter] will be +1, and the printing order of the console is as follows:

  • Child component: getDerivedStateFromProps()

  • Child component: shouldComponentUpdate()

  • Child component: render()

  • Child component: getSnapshotBeforeUpdate()

  • Child component: componentDidUpdate()

Modify the props passed to the child component in the parent component

Click the [change the attribute count passed to the child component] button in the parent component, then the value of [attribute count passed from the parent component] on the interface will be + 1, and the printing order of the console is as follows:

  • Parent component: getDerivedStateFromProps()

  • Parent component: shouldComponentUpdate()

  • Parent component: render()

  • Child component: getDerivedStateFromProps()

  • Child component: shouldComponentUpdate()

  • Child component: render()

  • Child component: getSnapshotBeforeUpdate()

  • Parent component: getSnapshotBeforeUpdate()

  • Child component: componentDidUpdate()

  • Parent component: componentDidUpdate()

Uninstall subcomponents

Click the [Uninstall/Mount child component] button in the parent component, the child component will disappear on the interface, and the printing sequence of the console is as follows:

  • Parent component: getDerivedStateFromProps()

  • Parent component: shouldComponentUpdate()

  • Parent component: render()

  • Parent component: getSnapshotBeforeUpdate()

  • Child component: componentWillUnmount()

  • Parent component: componentDidUpdate()

5. Remount child components

Click the [Uninstall/Mount child component] button in the parent component again, then the child component will be rendered again on the interface, and the printing order of the console is as follows:

  • Parent component: getDerivedStateFromProps()

  • Parent component: shouldComponentUpdate()

  • Parent component: render()

  • Child component: constructor()

  • Child component: getDerivedStateFromProps()

  • Child component: render()

  • Parent component: getSnapshotBeforeUpdate()

  • Child component: componentDidMount()

  • Parent component: componentDidUpdate()

Summary of parent-child component lifecycle execution order:

  • When the state of the child component changes, the parent component does not update, that is, it does not trigger the life cycle of the parent component

  • When the state of the parent component changes (including mounting and unmounting of the child component), it triggers its own lifecycle and updates of the child component

    • render As well asrenderBefore the life cycle, the parent component executes first
    • renderAs well asrenderIn subsequent declaration cycles, the child component executes first and alternates with the parent component

    When a child component is unmounted, only its own componentWillUnmount life cycle is executed and no other life cycle is triggered

    This is my knowledge points according to their own summary, if there is insufficient, you can leave a message for me to correct. Finally, I hope you can give me more thumbs up + attention, your recognition is my motivation to move forward!

The sample code

If you need to test, please click the code location