• Scotland team
  • Author: Dee

componentWillMount
componentWillReceiveProps
componentWillUpdate
UNSAFE_
UNSAFE_

Why alarm these life cycle functions?

1, componentWillMount

The componentWillMount life cycle occurs before the first rendering, and is where most of the regular users initialize data or get external data assignments asynchronously. To initialize data, use Constructor as the official recommendation for React. While asynchronously fetching external data, rendering does not wait for the data to return.

Case 1: The following is an example of a component that listens for an external event scheduler at installation time

class Example extends React.Component {   
    state = {
        value: ' '
    };
    componentWillMount() {    
        this.setState({       
            value: this.props.source.value
        });       
        this.props.source.subscribe(this.handleChange);
    }   
    componentWillUnmount() {    
        this.props.source.unsubscribe(this.handleChange ); 
    }   
    handleChange = source => {    
        this.setState({
            value: source.value
        });   
    }; 
}
Copy the code

Imagine if the component was broken during the first rendering, and the component did not execute the componentWillUnmount life cycle because the component did not complete the rendering. Many people often assume that componentWillMount and componentWillUnmount are always paired, but this is not always the case. React is guaranteed to call componentWillUnmount later for cleanup only after calling componentDidMount. Therefore, handleSubscriptionChange will still be executed after the data is returned successfully, and setState will cause a memory leak because the component has been removed. It is recommended that asynchronous fetching external data be written into the componentDidMount life cycle to ensure that the componentWillUnmount life cycle is executed when the component is removed, avoiding the risk of a memory leak.

ComponentWillMount UNSAFE_componentWillMount UNSAFE_componentWillMount UNSAFE does not refer to security, but rather code that uses these lifecycleswill be more likely to be flawed in future React versions, especially once asynchronous rendering is enabled.)

2, componentWillReceiveProps

ComponentWillReceiveProps lifecycle is triggered when props to update. This parameter is used to update the state parameter when the props parameter is updated. But if the direct call father componentWillReceiveProps lifecycle components of certain call setState function, will cause the program to death cycle.

Case 2: the following is a subcomponent componentWillReceiveProps call father component change state function example

. class Parent extends React.Component{constructor(){
        super();
        this.state={
            list: [],
            selectedData: {}
        };
    }
    
    changeSelectData = selectedData => {
        this.setState({
            selectedData
        });
    }
    
    render() {return( <Clild list={this.state.list} changeSelectData={this.changeSelectData}/> ); }}... class Child extends React.Component{constructor(){ super(); this.state={ list: [] }; } componentWillReceiveProps(nextProps){ this.setState({ list: nextProps.list }) nextProps.changeSelectData(nextProps.list[0]); // The default is to select the first}... }Copy the code

The above code, in the Child components componentWillReceiveProps direct call the Parent component changeSelectData to update the Parent component selectedData value of the state. Will trigger the Parent component to apply colours to a drawing, and the Parent component to render will trigger a Child component function performs componentWillReceiveProps life cycle. Then you get stuck in a loop. The program crashes.

So the React official componentWillReceiveProps replaced with UNSAFE_componentWillReceiveProps, let the junior partner in the use of the life cycle of time attention it will have defects, should pay attention to avoid, such as in the above example, Child when changeSelectData componentWillReceiveProps call to judge whether the list is updated to make sure whether to call, you can avoid death cycle.

3, componentWillUpdate

The componentWillUpdate life cycle is triggered before the view is updated. It is generally used to save some data before the view is updated to facilitate the assignment of values after the view is updated. Case 3: The following is a case where the list returns to the current scrollbar position after loading the update

class ScrollingList extends React.Component {   
    listRef = null;   
    previousScrollOffset = null;   
    componentWillUpdate(nextProps, nextState) {    
        if (this.props.list.length < nextProps.list.length) {      
            this.previousScrollOffset = this.listRef.scrollHeight - this.listRef.scrollTop;    
        } 
    }   
    componentDidUpdate(prevProps, prevState) {    
        if (this.previousScrollOffset !== null) {      
            this.listRef.scrollTop = this.listRef.scrollHeight - this.previousScrollOffset;  
            this.previousScrollOffset = null;    
        }   
    }   
    render() {    
        return( `<div>` {/* ... contents... */}`</div>` ); }setListRef = ref => {    this.listRef = ref;   };
}
Copy the code

Because componentWillUpdate and componentDidUpdate have two life cycle functions, there is a certain time difference (componentWillUpdate after rendering, calculation, and then update DOM element, finally call componentDidUpdate), If the user just stretched the browser height during that time, the previousScrollOffset calculated by componentWillUpdate is not accurate. If the setState operation is performed in componentWillUpdate, there will be a problem of calling setState only once. Put setState in componentDidUpdate to ensure that each update is called only once.

React recommends replacing componentWillUpdate with UNSAFE_componentWillUpdate. If you really need the above case, you can use getSnapshotBeforeUpdate, a periodic function added in 16.3. There will be specific instructions below, but I’ll keep them in suspense.

What are the alternatives?

1, getDerivedStateFromProps

GetDerivedStateFromProps is a new lifecycle function added in 16.3. This function is called when props changes, or when the parent component is rerendered. It returns the new props value.

Example 4: The following is an example of getDerivedStateFromProps

class Example extends React.Component {   
    static getDerivedStateFromProps(nextProps, prevState) { 
        if(nextProps.name ! == prevState.name) {return {
                name: nextProps.name
            }
        }
    } 
}
Copy the code

As you can see, getDerivedStateFromProps takes the latest Props value nextProps and the previous state value prevState, and returns either an object to update the state, or null to indicate that the state does not need to be updated. Note that getDerivedStateFromProps cannot access this, so if you want to compare the previous props value, you need to store the previous props value in state as a mirror. Why don’t you pass the previous props value to getDerivedStateFromProps? The official explanation is as follows:

  • When getDerivedStateFromProps is called for the first time (after instantiation), the prevProps parameter will be null. You need to add an if-not-NULL check when accessing prevProps.

  • No previous props was passed to this function, a step to free up memory in future versions of React. (If React doesn’t need to pass the previous item to the lifecycle, it doesn’t need to keep the previous item object in memory.)

In conclusion, official getDerivedStateFromProps is new to replace componentWillReceiveProps solution. If your project is considering compatibility with later versions, use getDerivedStateFromProps instead.

2, getSnapshotBeforeUpdate

GetSnapshotBeforeUpdate is a new lifecycle function added in 16.3, along with getDerivedStateFromProps. Fires before the most recent change is committed to the DOM element, allowing the component to get the current value before it changes. Any value returned by this lifecycle is passed to componentDidUpdate as a third parameter. This lifecycle is usually used when we need to save the current state of the DOM before updating the DOM. It is more commonly used to get the scroll position before updating the DOM and then revert to the scroll position after updating the DOM. For example, getSnapshotBeforeUpdate is a better alternative to componentWillUpdate. GetSnapshotBeforeUpdate to componentDidUpdate only updates the DOM.

Case 5: The following is a better alternative to case 3

class ScrollingList extends React.Component {   
    listRef = null;   
    getSnapshotBeforeUpdate(prevProps, prevState) {    
        if (prevProps.list.length < this.props.list.length) {      
            return this.listRef.scrollHeight - this.listRef.scrollTop;    
        } 
        return null;
    }   
    componentDidUpdate(prevProps, prevState, snapshot) {    
        if (snapshot !== null) {      
            this.listRef.scrollTop = this.listRef.scrollHeight - snapshot;   
        }   
    }   
    render() {    
        return( `<div>` {/* ... contents... */}`</div>` ); }setListRef = ref => {    this.listRef = ref;   };
}
Copy the code

Finally, for the replacement of componentWillMount, the official recommendation is to put the logic handling of the life cycle function into componentDidMount.

As the React version iterates, will the UNSAFE class lifecycle be compatible

The React website has the following plans:

  • 16.3: alias UNSAFE_componentWillMount, introduced for safety lifecycle, UNSAFE_componentWillReceiveProps and UNSAFE_componentWillUpdate. (Both the old lifecycle name and the new alias are available in this release.)

  • The next 16. X version: for componentWillMount, componentWillReceiveProps and componentWillUpdate enable deprecation warnings. (Both the old lifecycle name and the new alias are available in this release, but the old name logs the DEV mode warnings.)

  • 17.0: delete componentWillMount componentWillReceiveProps and componentWillUpdate. (From now on, only the new “UNSAFE_” life cycle name will work.)

conclusion

Actually, all that said. Just two points:

1, React to realize componentWillMount, componentWillReceiveProps and componentWillUpdate these three lifecycle function flawed, and are more likely to lead to collapse. However, because older projects already use these lifecycle functions and some older developers are used to them, they are alerted to their defects by adding UNSAFE_ to them.

React has added two new lifecycle functions, getSnapshotBeforeUpdate and getDerivedStateFromProps. The purpose is to implement functions that only the three lifecycle functions can implement without using the three lifecycle functions.

Ps: Part of this article is based on the upcoming life cycle changes in Reference article ReactV16.3