React 怎么理解`setState`是异步这回事?

hiveer · November 06, 2019 · Last by Mark24 replied at October 29, 2020 · 5789 hits

Google 了很久没有找到我要的答案:

问题 1

在 React re-render 被真正执行前,state 是不是必须已经被更新了 或者说setState的异步操作必须执行完了,才会真的去 call re-render

问题 2

虽然 setState 是异步的,但是由它导致的 component 生命周期方法的执行并不是异步的? 比如,假设我有如下的代码

method {
  setState();   #1
  updateOthers(); #2
}

componentWillUpdate(); #3

render() #4

上述代码的执行顺序是不是 #1 #3 #4 #2
还是说 是不一样的执行顺序?

https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

为什么说 setState 是异步的跟这对我们的影响可以看官网的文档。 我的理解是这样子,假如组件方法里有段代码是这样子

// 假设 this.state.counter 原先的值为 0
this.setState({
  counter: 1,
});

this.setState({
  // 文档说了为了性能多个 setState 调用可能合并成一个单独的状态更新
  // 那么这里 this.state.counter 的值是 0 还是 1 呢? 
  counter: this.state.counter + 1, 
});

@IchiNiNiIchi 谢谢回复。你举的这个例子,比较好理解。 也就是说setState对 state 数据的更新是可能存在延时的。但是即使我知道了这点,上面文章的问题还是存在。 我准备自己再深入研究下,如果有结果会这里更新。

Reply to hiveer

我觉得你有点钻太深了,要得到答案估计得研究实现的代码。当成黑盒就比较好理解,setState 是异步这一点需要我们去注意就只有当要根据当前组件 state 推导新的 state 的时候。

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {counter: 0};
  }

  componentDidUpdate() {
    console.log(this.state.counter)
  }

  handleClick = () => {
    this.setState((state, props) => ({
      counter: state.counter + 1
    }))
    this.setState((state, props) => ({
      counter: state.counter + 1
    }))
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
        <h2>{this.state.counter}</h2>
      </div>
    );
  }
}

// ========================================

ReactDOM.render(
  <Counter />,
  document.getElementById('root')
);

另外 componentWillUpdate 文档不推荐使用了。上面这段代码实验了一下,handleClick 执行了两次 setState,不过 componentDidUpdate 只执行了一次。你提的那些问题要想深究,可以自己写代码测试一下。

  • 问题一

你可以那么理解,因为他在更新之前会有检查

  • 问题二

感觉你把代码执行和生命周期给搞混了。

首先你说他是异步,那你可以理解大致成 setTimeout。

其实他是不是异步还是看具体情况,合成事件里调用的时候是异步的。

至于生命周期你可以看看这个

主要就是更新时的生命周期,多看看文档哦。

源码里就是,收集起来一段时间 再更新。所以是异步的。

如果你希望更新后做点什么,可以使用 setState 第二个参数,是一个回调,那里会返回最新值。

You need to Sign in before reply, if you don't have an account, please Sign up first.