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 值纔是正確的作法!

相關文章
相關標籤/搜索