react的setState使用详解

react修改状态是不能直接修改的,需要使用setState来进行状态的修改,但是setState的使用会存在一些问题。觉得有必要在此做一下总结。。。。

setState()不是立刻更新组件。其可能是批处理或推迟更新。这使得在调用setState()后立刻读取this.state的一个潜在陷阱。

就像这样:

incrementCount() {
  this.setState({count: this.state.count + 1});
}
handleSomething() {
  this.incrementCount();
  this.incrementCount();
  this.incrementCount();
}
调用了3次incrementCount方法, 期望this.state.count的值是3, 但最后却是1

本质上setState修改state的值是通过浅合并把新的值合并到state的对象上,如果多次修改,react会进行批次处理

类似于:

Object.assign(
  previousState,
  {count: state.count + 1},
  {count: state.count + 1},
  {count: state.count + 1},
)
之后的调用在同一周期中将会重写之前调用的值,因此数量仅会被加一。若之后的状态依赖于之前的状态,

解决这个问题的方式:

componentDidUpdate或一个setState回调(setState(updater, callback))

  1. 当中的每个方法都会保证在更新被应用之后触发
  2. updater函数接收到的prevState 和 props保证都是最新的
incrementCount() {
  this.setState((state) => {
    return {count: state.count + 1}
  });
}
handleSomething() {
  this.incrementCount();
  this.incrementCount();
  this.incrementCount();
}

setState什么时候会异步更新

setState的执行流程:

this.setState(newState)
==>
newState存入pending队列
==>
判断是否处于batch update
==>
如果是的话就保存组件月dirtyComponents中,
如果不是的话就遍历所有的dirtyComponents,调用updateComponent,更新pending state or props

在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中回头再说,
而 isBatchingUpdates 默认是 false,也就表示 setState 会同步更新 this.state,
但是,有一个函数 batchedUpdates,这个函数会把 isBatchingUpdates 修改为 true,
而当 React 在调用事件处理函数之前就会调用这个 batchedUpdates,造成的后果,就是由 React 控制的事件处理过程 setState 不会同步更新 this.state。

  • setState会导致re-rederning, 而re-rederning的代价是昂贵的, 所以他们会尽可能的把多次操作合并成一次提交。
  • 因为当传入的是一个函数时,state读取的是pending队列中state的值

setState什么时候会异步更新, 什么时候会同步更新

React是根据isBatchingUpdates来合并更新的, 那么当调用setState的方法或者函数不是由React控制的话, setState自然就是同步更新了。

  1. 如componentDidMount等生命周期以及React的事件即为异步更新,这里不显示具体代码。
  2. 如自定义的浏览器事件,setTimeout,setInterval等脱离React控制的方法, 即为同步更新

推荐阅读更多精彩内容