You don't know React's setState() to update data asynchronously and its solution

Work together to create and grow together! This is the 21st day of my participation in the "Nuggets Daily New Plan · August Update Challenge", click to view the details of the event

1. Description of setState()

I believe everyone uses React a lot, but did you know that React's setState() method updates data asynchronously? Below we will use an example to analyze how setState() updates data asynchronously, and what should be paid attention to during use.

1.1 Update data

setState() updates data asynchronously

As we all know, React uses setState() to update data, but in fact, setState() updates data asynchronously. The code is as follows:

// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// App组件
class App extends React.Component {
  // 默认状态的值
  state = {
    count: 1
  }
  
  handleClick = () => {
    // 异步更新state
    this.setState({
      count: this.state.count + 1
    })
    console.log(this.state.count)// 1
    
  }
  
  render() {
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
复制代码

In the above code, we have a default value of 1 and provide a handler for the click event, when the button is clicked once, we +1 on that default value, making the value of count 2, but because We print this.state.count directly after the this.setState() method, then the value we actually get is still 1, indicating that although the this.setState() method call is over, the state is not updated immediately, which also proves that this.setState() updates data asynchronously. The demonstration effect is as follows:

1.gif

Note: When using this syntax, the following setState() should not depend on the preceding setState()

In fact, this.setState() can be called multiple times, but since this.setState() updates data asynchronously, the second this.setState() is called after the first this.setState() is called. The result will not change. code show as below:

// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// App组件
class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
    // 前面的setState()
    this.setState({
      count: this.state.count + 1// 1 + 1
    })
    console.log('第一次调用完的count:', this.state.count)// 1

    // 后面的setState()
    this.setState({
      count: this.state.count + 1
    })
    console.log('第二次调用完的count:', this.state.count)// 1
  }

  render() {
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
复制代码

The effect is as follows:

2.gif

setState() can be called multiple times, but only one re-render will be called

Although this.setState() is called twice, render() is only executed once (it is not counted during initialization, only after clicking the button), this is for better performance, and it will not be reset every time the state changes. Render the page. code show as below:

// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// App组件
class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
    // 前面的setState()
    this.setState({
      count: this.state.count + 1// 1 + 1
    })
    console.log('第一次调用完的count:', this.state.count)// 1

    // 后面的setState()
    this.setState({
      count: this.state.count + 1
    })
    console.log('第二次调用完的count:', this.state.count)// 1
  }

  render() {
    console.log('render调用')
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
复制代码

The effect is as follows:

3.gif

1.2 Recommended syntax

If the later this.setState() wants to perform operations based on the result of the first this.setState(), how should it be implemented? Methods as below:

  • Recommended: use setState((state,props) => {}) syntax
  • Parameter state: indicates the latest state
  • Parameter props: indicates the latest props
// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// App组件
class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
    // 前面的setState()
    // 更新state
    // 注意:这种方法也是异步更新数据
    this.setState((state, props) => {
      return {
        count: state.count + 1// 1 + 1
      }
    })

    // 后面的setState()
    this.setState((state, props) => {
      console.log('第二次调用:', state)
      return {
        count: state.count + 1
      }
    })
    console.log('count:', this.state.count)// 1
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
复制代码

The effect is as follows:

1.gif

1.3 The second parameter of setState()

  • Scenario: Do ​​something right after a state update (page finishes re-rendering)
  • Syntax: setSate(updater,[callback])
this.setState(
    (state, props) => {},// 参数1
    () => {console.log('这个回调函数会在状态更新后立即执行')}// 参数2
)
复制代码

In fact, the setState() method has a second parameter, which is a callback function. This callback function will be executed immediately after the state update, so if you want to do something after the state update, you can go in this callback function. Execute, its usage is as follows:

// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// App组件
class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
    this.setState(
      // 参数1
      (state, props) => {
        return { count: state.count + 1 }
      },

      // 参数2:在状态更新后且重新渲染后,立即执行
      () => {
        console.log('状态更新完成:', this.state.count)
        console.log(document.getElementById('title').innerText)
        document.title = '更新后的count为:' + this.state.count
      }
    )
    console.log("异步执行完以后的count:"+this.state.count)// 1
  }

  render() {
    return (
      <div>
        <h1 id='title'>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
复制代码

The effect is as follows:

2.gif

Guess you like

Origin juejin.im/post/7133127251704922126