react的setState()的同步和异步

175 阅读1分钟

大家都知道,react中的state不能直接修改,只能通过setState()来修改。

setState()的更新可能是异步的

异步的情况:

  • 出于性能考虑,react会把多个setState()调用合并成一个。 代码如下: 观察控制台的打印与页面上counter的值,发现不同步。
changeValue = v => {
    this.setState(
      {
        counter: this.state.counter + v
      })
    console.log('counter不同步====', this.state.counter);//不同步,如果不用setTimout 和setState回调的话

  }

  setCounter = () => {
    //setState在setTimout和原生事件中是同步的
    this.changeValue(1);
    
    // console.log('this.state.counter====', this.state.counter);
  }
  render() {
    const { counter } = this.state
    return (
      <div>
        <h3>setStatePage</h3>
        <button onClick={this.setCounter}>{counter}</button>
        <button id="test">原生事件:{counter}</button>
      </div>
    )
  }

如上图,页面上的counter与控制台中的不同步。 另个,如果在setCounter函数中再写一个this.changeValue(2),则只会调用this.changeValue(2),this.changeValue(1)不会调用,这也是react会把setState中的调用合并的原因。

setCounter = () => {
    this.changeValue(1);
    this.changeValue(2);  //只会调用这个,上面的this.changeValue(1)不会被调用
    
    // console.log('this.state.counter====', this.state.counter);
  }

同步的情况

  • 在回调中获取状态值
changeValue = v => {
    this.setState(
      {
        counter: this.state.counter + v
      },
      () => {
        console.log('counter同步====', this.state.counter);
      }
    )
    //console.log('counter不同步====', this.state.counter);//不同步,如果不用setTimout 和setState回调的话

  }
  • 在setTimeout中调用changeValue
setCounter = () => {
    //setState在setTimout中是同步的
    
    setTimeout(() => {
      this.changeValue(1);
      this.changeValue(2);  //两个changeValue都运行所以一共是加3 ,先加1,再加2

    }, 1000)
  }
  • 在原生事件中是同步的
 componentDidMount() {
    document.getElementById("test").addEventListener('click', this.setCounter)
  }
  render() {
    const { counter } = this.state
    return (
      <div>
        <button id="test">原生事件:{counter}</button>
      </div>
    )
  }

总结:setState只在合成事件和生命周期函数中是异步的,在原生事件和setTimeout中都是同步的。