“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 created
beforeCreate
Hook function; - After component creation
created
Hook function; - Components before mounting
beforeMount
Hook function; - After the component is mounted
mounted
Hook function; - Component before update
beforeUpdate
Hook function; - After component update
updated
Hook function; - Before component destruction
beforeDestroy
Hook function; - After component destruction
destroyed
Hook 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 statement
super(props)
, otherwise,this.props
forundefined
; - Initialize state by assigning the this.state object;
- Bind the instance to the event handler, otherwise it cannot be used in the function
this
.
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 use
this.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 function
this
.
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 in
componentWillUnmount()
Cancel listening; - You can call
this.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 the
componentDidMount
The 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