Summary of setState learning in React

Keywords: Javascript React

Whether the setState method in react is asynchronous or synchronous depends on the conditions.

1. Let's review several ways to change state in react component:

import React, { Component } from 'react'

class Index extends Component {
    state={
        count:1
    }
    test1 = () => {
        // Through the form of callback function
        this.setState((state,props)=>({
            count:state.count+1
        }));
        console.log('test1 setState()after',this.state.count);
    }
    test2 = () => {
        // Through objects(Note: multiple settings of this method will be merged and only called once!)
        this.setState({
            count:this.state.count+1
        });
        console.log('test2 setState()after',this.state.count);
    }
    test3 = () => {
        // Cannot be modified directly state This method is strongly not recommended!!! Because it doesn't trigger a reboot render
        this.state.count += 1;
    }
    test4 = () => {
        // In second callback Get the updated state
        this.setState({
            count:this.state.count+1
        },()=>{// Update in status and page update(render)Post execution
            console.log('test4 setState()after',this.state.count);
        });
    }
    render() {
        console.log('render');
        return (
            <div>
                <h1>currentState:{this.state.count}</h1>
                <button onClick={this.test1}>Test 1</button>
                <button onClick={this.test2}>Test 2</button>
                <button onClick={this.test3} style={{color:'red'}}>Test 3</button>
                <button onClick={this.test4}>Test 4</button>
            </div>
        )
    }
}
export default Index;

2. Whether setstate() updates the state asynchronously or synchronously:

Need to determine where to execute setState

Synchronization: in the callback function controlled by react: life cycle hook / react event listening callback

import React, { Component } from 'react'

class Index extends Component {
    state={
        count:1
    }
    /* 
    react In the event listening callback, setState() is asynchronous
    */
    update1 = () => {
        console.log('update1 setState()before',this.state.count);
        this.setState((state,props)=>({
            count:state.count+1
        }));
        console.log('update1 setState()after',this.state.count);
    }
    /* 
    react In the lifecycle hook, setState() is the asynchronous update state
    */
    componentDidMount() {
        console.log('componentDidMount setState()before',this.state.count);
        this.setState((state,props)=>({
            count:state.count+1
        }));
        console.log('componentDidMount setState()after',this.state.count);
    }
    
    render() {
        console.log('render');
        return (
            <div>
                <h1>currentState:{this.state.count}</h1>
                <button onClick={this.update1}>Test 1</button>
                <button onClick={this.update2}>Test 2</button>
            </div>
        )
    }
}
export default Index;

Asynchronous: non react controlled asynchronous callback functions: timer callback / native event listening callback / Promise

import React, { Component } from 'react'

class Index extends Component {
    state={
        count:1
    }
    /* 
    Timer callback
    */
    update1 = () => {
        setTimeout(()=>{
            console.log('setTimeout setState()before',this.state.count);//1
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('setTimeout setState()after',this.state.count);//2
        });
    }
    /* 
    Native event callback
    */
    update2 = () => {
        const h1 = this.refs.count;
        h1.onclick = () => {
            console.log('onClick setState()before',this.state.count);//1
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('onClick setState()after',this.state.count);//2
        }
    }
    /* 
    Promise Callback
    */
    update3 = () => {
        Promise.resolve().then(value=>{
            console.log('Promise setState()before',this.state.count);//1
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('Promise setState()after',this.state.count);//2
        });
    }
    
    render() {
        console.log('render');
        return (
            <div>
                <h1 ref='count'>currentState:{this.state.count}</h1>
                <button onClick={this.update1}>Test 1</button>
                <button onClick={this.update2}>Test 2</button>
                <button onClick={this.update3}>Test 3</button>
            </div>
        )
    }
}
export default Index;

3.setState() multiple calls:

Asynchronous setState()

(1) multiple calls, processing method:

setState({}): merge and update the state once, only call render() once to update the interface, multiple calls will be merged into one, and the later value will overwrite the previous value.

setState(fn): update multiple states, only call render() once to update the interface, multiple calls will not be merged into one, and the later value will overwrite the previous value.

import React, { Component } from 'react'

class Index extends Component {
    state={
        count:1
    }
    update1 = () => {
        console.log('update1 setState()before',this.state.count);
        this.setState((state,props)=>({
            count:state.count+1
        }));
        console.log('update1 setState()after',this.state.count);
        console.log('update1 setState()Previous 2',this.state.count);
        this.setState((state,props)=>({
            count:state.count+1
        }));
        console.log('update1 setState()After 2',this.state.count);
    }
    update2 = () => {
        console.log('update2 setState()before',this.state.count);
        this.setState({
            count:this.state.count+1
        });
        console.log('update2 setState()after',this.state.count);
        console.log('update2 setState()Previous 2',this.state.count);
        this.setState({
            count:this.state.count+1
        });
        console.log('update2 setState()After 2',this.state.count);
    }
    update3 = () => {
        console.log('update3 setState()before',this.state.count);
        this.setState({
            count:this.state.count+1
        });
        console.log('update3 setState()after',this.state.count);
        console.log('update3 setState()Previous 2',this.state.count);
        this.setState((state,props)=>({
            count:state.count+1
        }));// Attention is needed here setState When the parameter is in function mode, state Make sure you get the latest value
        console.log('update3 setState()After 2',this.state.count);
    }
    update4 = () => {
        console.log('update4 setState()before',this.state.count);
        this.setState((state,props)=>({
            count:state.count+1
        }));
        console.log('update4 setState()after',this.state.count);
        console.log('update4 setState()Previous 2',this.state.count);
        this.setState({
            count:this.state.count+1
        });// What should be noted here is that if setState Pass the parameter as the object and at the end, the setState merge
        console.log('update4 setState()After 2',this.state.count);
    }
    render() {
        console.log('render');
        return (
            <div>
                <h1>currentState:{this.state.count}</h1>
                <button onClick={this.update1}>Test 1</button>
                <button onClick={this.update2}>Test 2</button>
                <button onClick={this.update3}>Test 3</button>
                <button onClick={this.update4}>Test 4</button>
            </div>
        )
    }
}
export default Index;

(2) how to get the state data after asynchronous update of setState:

In the callback callback function of setState()

4. Common setState interview questions in react (setState execution order)

import React, { Component } from 'react'
// setState Execution sequence
class Index extends Component {
    state={
        count:0
    }
    componentDidMount() {
        this.setState({count:this.state.count+1});
        this.setState({count:this.state.count+1});
        console.log(this.state.count);// 2 => 0
        this.setState(state=>({count:state.count+1}));
        this.setState(state=>({count:state.count+1}));
        console.log(this.state.count);// 3 => 0
        setTimeout(() => {
            this.setState({count:this.state.count+1});
            console.log('setTimeout',this.state.count);// 10 => 6
            this.setState({count:this.state.count+1});
            console.log('setTimeout',this.state.count);// 12 => 7
        });
        Promise.resolve().then(value=>{
            this.setState({count:this.state.count+1});
            console.log('Promise',this.state.count);// 6 => 4
            this.setState({count:this.state.count+1});
            console.log('Promise',this.state.count);// 8 => 5
        });
    }
    render() {
        console.log('render',this.state.count);// 1 => 0  // 4 => 3 // 5 => 4 // 7 => 5 // 9 => 6 // 11 => 7
        return (
            <div>
                <h1>currentState:{this.state.count}</h1>
                <button onClick={this.update1}>Test 1</button>
                <button onClick={this.update2}>Test 2</button>
                <button onClick={this.update3}>Test 3</button>
                <button onClick={this.update4}>Test 4</button>
            </div>
        )
    }
}
export default Index;

Summary: two ways to write setState() update state in react

1)setState(updater,[callback])

updater: function to return stateChange object: (state, props) = > stateChange. Received state and props are guaranteed to be up-to-date

2)setState(stateChange,[callback])

stateChange is an object, and callback is an optional callback function, which is executed only after the status is updated and the interface is updated

Be careful:

Object is a shorthand for function

If the new state does not depend on the original state, the object mode is used;

If the new state depends on the original state, the function mode is used;

If you need to get the latest state data after setState(), get it in the second callback function

Posted by SimpleManWeb on Wed, 18 Dec 2019 14:22:10 -0800