React 中执行 setState 时怎么保证你取到的上一次state是正确的?

setState 是 React 用于管理状态的一个特殊函数,咱们在 React 中会常常使用到它,下面的场景你必定遇到过:react

export class Todo extends React.Component{
  ... 
  increaseScore () {
    this.setState({count : this.state.count + 1});
    this.setState({count : this.state.count + 1});
  }
  ...
}
复制代码

上面这段代码, increaseScore函数中但愿将 count 这个状态的值在原来的基础上加1再加1,可是实际状况其实并不想你预期的那样,若是你在控制台把count的值打出来,会发现它只增长了1!git

为何呢?github

setState 是异步的

setState 是异步的异步

看一下这个例子函数

class BadCounter extends React.Component{
  constructor(props){
    super(props);
    this.state = {count : 0} 
  }
  incrementCount=()=>{
    this.setState({count : this.state.count + 1}) 
    this.setState({count : this.state.count + 1})
  }
  render(){
    return <div> <button onClick={this.incrementCount}>+2</button> <div>{this.state.count}</div> </div>
  }
}

class GoodCounter extends React.Component{
  constructor(props){
    super(props);
    this.state = {count : 0} 
  }
  incrementCount=()=>{
   this.setState((prevState, props) => ({
      count: prevState.count + 1
    }));
   this.setState((prevState, props) => ({
      count: prevState.count + 1
    }));
  }
  render(){
    return <div> <button onClick={this.incrementCount}>+2</button> <div>{this.state.count}</div> </div>
  }
}
复制代码

在这个demo中,上下两个计数器都是但愿实现点击后数+2,可是实际效果以下,只有第二个计数器达到了咱们的预期:this

结合代码能够发现两个计数器的区别给setState 传递的参数不同spa

// 在错误示例中
this.setState({count : this.state.count + 1}) 
this.setState({count : this.state.count + 1}) 

// 在正确示例中
this.setState((prevState, props) => ({
  count: prevState.count + 1
}))
this.setState((prevState, props) => ({
  count: prevState.count + 1
}))
复制代码

查阅资料发现,在屡次调用setState()时,React 并不会同步处理这些setState()函数,而是作了一个“批处理”——若是使用对象做为参数传递给setState,React 会合并这些对象3d

而一样的状况下,当你给setState()传入一个函数时,这些函数将被放进一个队列,而后按调用顺序执行code

这里是react的核心成员 Dan Abramov 对 setState 为何是异步的解释cdn

总结

连续屡次执行 setState 操做的状况是很常见的,下一次你若是在 setState 时须要用到 this.state 的时候要切记,在 setState 中利用函数操做来取得上一次的 state 值才是正确的作法!

相关文章
相关标签/搜索