react的setState到底是同步還是異步?


在介紹這個問題之前,我們先來看一下一個例子:

state = {
    number:1
};
componentDidMount(){
    this.setState({number:3})
    console.log(this.state.number)
}

看完這個例子,也許很多小伙伴會下意識的以為setState是一個異步方法,但是其實setState並沒有異步的說法,之所以會有一種異步方法的表現形式,歸根結底還是因為react框架本身的性能機制所導致的。因為每次調用setState都會觸發更新,異步操作是為了提高性能,將多個狀態合並一起更新,減少re-render調用。

試想一下如果在組件中有以下這樣一段代碼執行:

for ( let i = 0; i < 100; i++ ) {
    this.setState( { num: this.state.num + 1 } );
}

如果setState是一個同步執行的機制,那么這個組件會被重新渲染100次,這對性能是一個相當大的消耗。

顯然,React也是想到了這個問題,因此對setState做了一些特殊的優化:

React會將多個setState的調用合並為一個來執行,也就是說,當執行setState的時候,state中的數據並不會馬上更新

這也很好的印證了剛才提到的那個例子。

但是往往在實際的開發工作中,我們可能需要同步的獲取到更新之后的數據,那么怎么獲取呢?下面介紹幾種常用的方法:

回調函數

setState提供了一個回調函數供開發者使用,在回調函數中,我們可以實時的獲取到更新之后的數據。還是以剛才的例子做示范:

state = {
    number:1
};
componentDidMount(){
    this.setState({number:3},()=>{
        console.log(this.state.number)
    })
}

這個時候大家可以看到控制台打印的數據就是最新的了,我們也就實時的獲取到了最新的數據。

setTimeout

上面我們講到了,setState本身並不是一個異步方法,其之所以會表現出一種異步的形式,是因為react框架本身的一個性能優化機制。那么基於這一點,如果我們能夠越過react的機制,是不是就可以令setState以同步的形式體現了呢?

說再多文字不如代碼實踐,實踐才是檢驗真理的唯一標准,下面我們還是以之前的例子為基礎改造一下代碼:

state = {
    number:1
};
componentDidMount(){
    setTimeout(()=>{
      this.setState({number:3})
      console.log(this.state.number)
    },0)
}

可以看見此時控制台打印的數據是最新的數據。這也完美的印證了我們的猜想是正確的。

原生事件中修改狀態

上面已經印證了避過react的機制,可以同步獲取到更新之后的數據,那么除了setTimeout以外,還有在原生事件中也是可以的。還是看一下例子:

state = {
    number:1
};
componentDidMount() {
    document.body.addEventListener('click', this.changeVal, false);
}
changeVal = () => {
    this.setState({
      number: 3
    })
    console.log(this.state.number)
}

經過實踐,同樣這種方法也是可行的。

總結:

setState本身並不是異步,只是因為react的性能優化機制體現為異步。在react的生命周期函數或者作用域下為異步,在原生的環境下為同步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM