Why React 16 changes the component lifecycle? (on)

React The Life cycle has been a platitudinarytopic. However, most introductory textbooks are designed to be “easy and quick to learn”, which leads to the stereotype of many people as “just memorize, don’t think too much”. Of course, the simple and crude learning method of “memorizing the whole thing” may help you understand “What to do” and “How to do”, but it cannot help you to think and recognize “Why to do”. As a professional React developer, we have to demand that we know what it is and why.

Therefore, in order to “know Why”, this chapter uses the basic principle of React as an introduction to discuss, compare and summarize the life cycle of React 15 and React 16 versions, and establish a systematic and perfect life cycle knowledge system by clarifying “Why” one after another.

1. Design Philosophy behind life Cycle: Understand the “big Picture” in React

Before we look at the life cycle, let’s take a look at some of the key design ideas in the React framework to provide an indispensable “acceleration” for subsequent learning.

React’s official website and some articles will find that the words “component” and “virtual DOM” are very popular. They are two key concepts in the basic principle of React, so let’s start with these two key concepts.

1) Virtual DOM: the cornerstone of core algorithms

In the JSX section of the previous chapter, we learned about the basic form of the virtual DOM node. Next, we need to briefly understand the role of the virtual DOM in the React workflow.

(1) The component is inInitialize theThe virtual DOM is generated by calling the Render method in the lifecycle, and then by callingReactDOM.renderMethod, implementVirtual DOM to real DOM conversion.

(2) When the component is updated, the render method is called again to generate a new virtual DOM, and then the difference between the two virtual DOM is located with the help of ** diff** (this is a very key algorithm, the core principle will be explained in the next module). To make targeted updates to the real DOM as it changes.

This is the basic flow of the React framework’s core algorithm. For this set of key workflows, the “virtual DOM” is the premise of all operations and the cornerstone of the core algorithm.

2) Componentization: the implementation of engineering thought in the framework

Componentization is an excellent software design idea and an important effort made by the React team in terms of r&d effectiveness.

In a React project, almost all visible/invisible content can be separated into various components, each of which is both “closed” and “open”.

(1) The so-called “closed” is mainly for the “rendering workflow” (refers to the process from component data changes to the actual update of the component). In the rendering workflow of the component itself, each component only deals with its internal rendering logic. In the absence of data flow interaction, components can be “independent” from one another.

(2) The so-called “open” is for communication between components. React allows developers to communicate between components based on “one-way data flow.” Communication between components in turn changes the internal data of both/one of the communicating parties, thus affecting the rendering results. Therefore, under the matchmaker of data, components are open to each other and can interact with each other.

This combination of “open” and “closed” makes the React component both focused and flexible, with a high degree of reuse and maintainability.

2. The nature of the Lifecycle Approach: The “soul” and “torso” of components

(1) “The Render method is like the soul of the React component.” Once you get to know the render method, you’ll find this sentence resonating. It’s important to note, however, that the Render method is not the same as the reactdom. render method, which refers to the lifecycle method inside the React component, as shown below:

Class LifeCycle extends React.Component {render() {console.log("render method executes "); return ( <div className="container"> this is content </div> ); }}Copy the code

For the previous understanding of “virtual DOM, componentization”, if the integration of these two pieces of knowledge, it will find that the two concepts seem to revolve around the life cycle of render: the virtual DOM needless to say, its generation depends on render; The “rendering workflow” mentioned in the concept of componentization refers to the process from component data change to the actual update of the component, and the realization of this process is also inseparable from render.

In this sense, the Render method really matters in the overall component lifecycle, and it deserves the “soul” metaphor.

(2) Then if the Render method is compared to the “soul” of the component, the life cycle method beyond render can be fully understood as the “torso” of the component.

The “body” doesn’t always do anything concrete (we can optionally omit writing any lifecycle method content other than render), while the “soul” is always fleshy (the render function is definitely not); If the “body” does something, it usually affects the “soul” directly or indirectly (because even the lifecycle logic outside of Render is mostly serving the render level effects); The “torso” and “soul” together form the complete and indivisible “life timeline” of the React component.

React life Cycle: React 15

React 16 is the most popular example of the React lifecycle. This saves a lot of work, but it also obscures the “Why” behind the changes in the old and new life cycles (more on the differences in the next chapter). Next, to explore “Why”, let’s look at the React 15 lifecycle process.

React 15 uses the following lifecycle methods:

constructor()
componentWillReceiveProps()
shouldComponentUpdate()
componentWillMount()
componentWillUpdate()
componentDidUpdate()
componentDidMount()
render()
componentWillUnmount()
Copy the code

If you’ve been around React long enough, you’ll probably remember the getDefaultProps and getInitState methods, both of which initialize data in React. CreateClass () mode. Since this notation has become less common in ES6, I won’t go into detail here.

(2) How do these lifecycle approaches cascade and depend on each other? Summed up in the following big picture:

Next, we’ll take a step-by-step look at how the component life cycle works around this big picture. During the learning process, the following Demo can help us verify the workflow of each stage concretely:

import React from "react"; import ReactDOM from "react-dom"; // Class LifeCycle extends React.Component {constructor(props) {console.log(" enter constructor"); super(props); // state can be initialized by constructor. State = {text: "child component text"}; } // Call componentWillMount() {console.log("componentWillMount method executes "); } // Call componentDidMount() {console.log("componentDidMount method executes "); } / / parent components modified components of props will call componentWillReceiveProps (nextProps) {the console. The log (" componentWillReceiveProps methods perform "); } shouldComponentUpdate(nextProps, nextState) {console.log("shouldComponentUpdate "); return true; } // componentWillUpdate(nextProps, nextState) {console.log("componentWillUpdate method execution "); } // componentDidUpdate(nextProps, nextState) {console.log("componentDidUpdate method execution "); } // Call componentWillUnmount() {console.log(" componentWillUnmount method executes for the child component "); } changeText = () => {this.setState({text: "modified child text"}); }; Render () {console.log("render method execution "); Return (<div className="container"> <button onClick={this.changeText} className="changeText"> modify the child component text </button> <p className="textContent">{this.state.text}</p> <p className="fatherContent">{this.props.text}</p> </div> ); }} // LifeCycle is defined as the parent of the LifeCycle component class LifeCycleContainer extends React.Component {// State can also be initialized as a property declaration like this. State = {text: "Parent component text ", hideChild: false}; ChangeText = () => {this.setState({text: "modified parent text"}); }; LifeCycle method hideChild = () => {this.setState({hideChild: true}); }; render() { return ( <div className="fatherContainer"> <button onClick={this.changeText} className="changeText"> </button> <button onClick={this.state.hidechild} className="hideChild"> </button> {this.state.hidechild? null : <LifeCycle text={this.state.text} />} </div> ); } } ReactDOM.render(<LifeCycleContainer />, document.getElementById("root"));Copy the code

In the index.html corresponding to the entry file, a real DOM node with the ID of root is preset as the root node. The content of the body tag is as follows:

<body>
  <div id="root"></div>
</body>
Copy the code

The Demo (the emphasis here is on validation of the lifecycle execution rules, so the style is kept simple) renders to the browser something like this:

(3) Let’s take a look at the Demo and the life cycle diagram at the beginningMount, update, and uninstallThe React component goes through all three phases.

Mounting Stage: Initial rendering (Mounting)

The mount process occurs only once in a component’s lifetime, during which the component is initialized and then rendered into the real DOM for what is called a “first render.”

During the mount phase, a React component goes through the life cycle shown below in sequence:

Mount stage details:

(I) First we look at the constructor method.

This method is called only once at mount time, and we can initialize this.state in this method:

Constructor (props) {console.log(" enter constructor"); super(props); // state can be initialized by constructor. State = {text: "child component text"}; }Copy the code
(ii) componentWillMount, componentDidMount methodAgain, it will only be called once during mount.

ComponentWillMount is triggered before the Render method is executed. Some people are used to doing initialization operations in this method, but these operations are often risky or unnecessary (for reasons explained in the next section).

(iii) Next the render method is fired.

Note that render does not manipulate the actual DOM during execution (that is, it does not render), its job is to render the content back. The actual DOM rendering is handled in the mount phase by reactdom.render.

(iv) componentDidMount method is triggered after rendering.

Because the real DOM is now mounted to the page, we can perform real DOM related operations during this lifecycle. In addition, operations such as asynchronous requests and data initialization can also be done in this lifecycle.

This entire process corresponds to the initial rendering process of the component when the Demo page is just opened. LifeCycle component in Demo is shown as console output during mount and can be used to verify the correct LifeCycle order during mount:

②Updating phase: component updates

Component updates are divided into two types: one is the update triggered by the parent component update; The other is an update triggered by the component itself calling its own setState. The corresponding lifecycle flow of these two updates is shown in the figure below:

(I) Updates triggered by the parent component

What is triggered by componentWillReceiProps? It is clear from the figure that updates triggered by the parent component have one more lifecycle method than updates by the component itself:

componentWillReceiveProps(nextProps)
Copy the code

In this lifecycle method, nextProps represents receiving the content of the new props, and the existing props (as opposed to the “old props” of nextProps) can be obtained by this. Props, so that the changes to the props can be perceived. For “change,” we need to dig a little deeper. In some communities, including some of the candidates interview answer, are seen/heard such a saying: componentWillReceiveProps is the component of props content changed when triggered. In fact, this statement is not rigorous. Without further ado, the console output of the interface looks like this after initialization:

Note that LifeCycleContainer, the parent component that passes LifeCycle props to the child component, has only one text:

<LifeCycle text={this.state.text} />
Copy the code

If you click the modify Parent text button,The this.state.text of the parent component changes, thus drivingThe this.props. Text of the child component changed. At this timeIs bound to trigger componentWillReceivePropsThis life cycle, there’s no doubt about it:

But if you now make a small change to the parent’s structure, give it a state (this.state.ownText) that is completely independent of the child, and give it a method to change the state accordingly (this.changeownText), The triggered action is followed by a new button.

The changed LifeCycleContainer looks like this:

Class LifeCycleContainer extends React.Component {// State can also be initialized with property declarations like this. State = {text: "Parent text ", // State ownText:" Parent text only ", hideChild: false}; ChangeText = () => {this.setState({text: "modified parent text"}); }; ChangeOwnText = () => {this.setstate ({ownText: "modified parent component's ownText"}); }; hideChild = () => { this.setState({ hideChild: true }); }; Render () {return (<div className="fatherContainer"> {/* new button */} <button onClick={this.changeowntext} </button> <button onClick={this.changeText} className="changeText"> Modify parent component text content </button> <button onClick={this.state.owntext} </p> {this.state.hideChild ? null : <LifeCycle text={this.state.text} />} </div> ); }}Copy the code

The new interface is shown below:

As you can see,This.state. ownText This state has nothing to do with the child component. But when you click on the modify parent component’s own text,ComponentReceiveProps is still triggeredThe effect is as follows:Hearing is but believing, seeing is believing. React runs like this: ComponentReceiveProps is not triggered by changes to props, but “triggered by updates to the parent component.This is a conclusion to keep in mind.

(ii) Updates triggered by the component’s own setState

Enclosing setState () callThe resulting update process has been reflected in the previous big picture. Here we directly use the previous Demo to demonstrate. If we click on the “Modify child component text content” button in the previous Demo:

This action is going toTrigger the update process for the child component LifeCycle itselfThe life cycle functions that are triggered are shown in the console content below:

Let’s look atComponentWillUpdate and componentDidUpdateThe two good gay friends.

ComponentWillUpdate is triggered before Render, which is similar to componentWillMount and allows you to do some preparatory work in it that doesn’t involve actual DOM manipulation; ComponentDidUpdate is triggered when a component is updated, and like componentDidMount, this lifecycle is often used to handle DOM operations. In addition, we often notify the parent component of the execution of componentDidUpdate as a sign that the child component has been updated.

Render and performance: shouldComponentUpdate

The shouldComponentUpdate lifecycle method should be mentioned here, which is called as follows:

shouldComponentUpdate(nextProps, nextState)
Copy the code

The Render method can be quite time-consuming due to the construction and comparison of the virtual DOM. In React, there are a lot of times when we accidentally call Render a lot. React provides shouldComponentUpdate to avoid the performance overhead of unnecessary render operations.

The React component uses the return value of shouldComponentUpdate to determine whether to re-render the component after the life cycle of the method. ShouldComponentUpdate defaults to true, that is, “unconditional re-render”. In real development, we often implement “conditional re-render” by manually populating the decision logic in shouldComponentUpdate or directly introducing best practices such as PureComponent into the project.

ShouldComponentUpdate and PureComponent optimizations for React will be discussed in the performance section below. So it’s just a matter of recognizing the basic use of shouldComponentUpdate and its relationship to React performance.

(3) Unmounting: Components are uninstalled

The component destruction phase itself is relatively simple and involves only one life cycle, as shown in the following figure:

As with the Demo above LifeCycle can be removed from the parent by clicking ‘Hide child component’. The whole process is shown below:

The lifecycle itself is not difficult to understand, but the key is how to trigger it. There are two common reasons for component destruction.

(I) The component is in the parentHas been removedThis situation is relatively straightforward and corresponds to the process described above.
(ii) ComponentsThe key property is setIf the parent component finds that the key value is different from the last one during render, the component will be killed.

In this module, the first reason is understood. For reason two, just remember that there is such a phenomenon. Why do components have keys inside them, and why do components have to be killed if the key changes? To answer the above two questions, you need to first understand the “reconciliation process” of React, which will be the focus of other modules in the following.

4, summarize

In this class, I had a preliminary understanding of the two key concepts of “virtual DOM” and “componentization” in React design, and also systematically studied and summarized the life cycle in React 15. Here’s how the React lifecycle looked over a long period of time.

In React 16, the component lifecycle has actually changed in a number of ways. See the details of the changes in the next class. The ancients said that “history as a mirror, can know the rise and fall.” Next, the React life cycle is compared with the old one to explore the motivation of the change.

Learning the source (the article reprinted from) : kaiwu.lagou.com/course/cour…