摘要:而在第二個參數中我們輸出了改變后的即第五行輸出,表明我們的更改生效了。而在的回調內,我們還調用了一個定義于內的事件函數,但是該事件函數內的也是同步的形式。
在react中,setState是用以改變class組件狀態的函數,它有兩種用法:
一 傳入一個updater函數,該函數有兩個參數,一個是當前的state,還有一個是當前的props。該函數的返回值需要是一個更改的state值的對象,它將于state進行淺合并,其用法如下:
this.setState((state, props) => { return { count: state.count + props.number }; });
二 直接傳入一個對象:
this.setState({ count: this.state.count + this.props.number });
setState函數還可以接受第二個參數,該參數為一個函數,將在更改的State生效之后調用:
console.log(this.state.count); // 1 this.setState({ count: 0 }, () => { console.log(this.state.count); // 0 }); console.log(this.state.count); // ? 此處即可能是1,也可能是0
從上面代碼可以看到,最后一行輸出的count是不固定的,這是為什么呢?
因為在react中,class內的事件處理程序會默認進行批處理,即如果你在componentDidMount里面調用三次setState函數,那么它最終會在componentDidMount執行完畢后,將三個State的更改合并為一次調用。所以這時候setState就是異步的。
而在其他場景下,setState將會是同步的,例如setTimeout內, Promise的then里面。
一個簡單的例子:
class SetStateExample extends Component { constructor() { super(); this.state = { count: 0 }; this.onClick = this.onClick.bind(this); } componentDidMount() { console.log("componentDidMount before", this.state.count); this.setState({ count: this.state.count + 1 }); console.log("componentDidMount after", this.state.count); } onClick() { console.log("onClick before", this.state.count) this.setState({ count: this.state.count + 1 }, () => { console.log("setState callback", this.state.count); }); console.log("onClick after", this.state.count); Promise.resolve().then(() => { console.log("promise.then before", this.state.count); this.setState({ count: this.state.count + 1 }); console.log("promise.then after", this.state.count); this.onClassEvent(); }); } onClassEvent() { console.log("onClassEvent before", this.state.count); this.setState({ count: this.state.count + 1 }); console.log("onClassEvent after", this.state.count); } render() { return; } }count: {this.state.count}
讓我們運行結果:
首先第一第二行輸出是在componentDidMount里面,我們在函數內調用了setState,并在前后分別輸出了改變的值,結果表明,函數調用前與函數調用后該值并沒有立即改變,則表明在這里setState是一個異步調用。那么初步判定在生命周期函數內部,setState是異步的調用。
然后第三第四行輸出是在onClick函數的回調里面,該函數定義在class中,通過用戶點擊觸發。在setState調用前后我們的輸出結果是一致的,這也表明其是一個異步調用。而在setState第二個參數中我們輸出了改變后的count, 即第五行輸出,表明我們的更改生效了。
然后第六行以后的輸出是我們在onClick函數內調用了promise.resolve().then()輸出的,它是一個異步調用,react是無法知道它什么時候執行,什么時候完成執行的,所以這時候react默認setState是同步的。從輸出我們可以看到每次更改之后,state的值都是立即變化生效的。
而在promise的回調內,我們還調用了一個定義于class內的事件函數,但是該事件函數內的setState也是同步的形式。這說明了setState的同步或者異步與其定義位置并沒有直接的關系,而應該取決于是否由React直接進行調用,因為只有是React直接調用的情況下,它才知道該函數什么時候執行完畢,才能進行批處理的優化。否則則默認是同步的調用。(具體內部實現就不展開了,因為我也不是特別懂HHHH,反正意思就大概是這么個意思)
所以當在一些回調內部調用setState時應該注意將多個setState合并,因為它是同步的,多次更新狀態會很影響性能。
以及需要注意進行異步調用的時候,如果需要使用變化后的值,請確保在異步調用完成后,一般是在setState的回調內,或者在componentDidUpdate鉤子內,但是請注意小心使用,因為很容易一不小心導致循環調用而崩潰。
如果你想在本應同步調用的回調內,對setState進行異步調用,即讓它進行批處理,React也提供了一個API:
promise.then(() => { // Forces batching ReactDOM.unstable_batchedUpdates(() => { this.setState({a: true}); // Doesn"t re-render yet this.setState({b: true}); // Doesn"t re-render yet this.props.setParentState(); // Doesn"t re-render yet }); // When we exit unstable_batchedUpdates, re-renders once });
在unstable_batchedUpdates內部進行的setState會是異步調用,但是該API是不穩定的,因為后續的React版本更新中將會默認進行批處理即異步調用,屆時該API將被刪除。而這個后續的版本,很可能就是React 17
記錄與分享,歡迎斧正,虛心求教
參考連接:
https://stackoverflow.com/que...
https://react.docschina.org/d...
https://github.com/Advanced-F...
https://github.com/sisterAn/b...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106941.html
摘要:判斷當前是否處于批量更新狀態,如果是,將當前組件加入待更新的組件隊列中。將組件的暫存隊列中的進行合并,獲得最終要更新的對象,并將隊列置為空。執行生命周期,根據返回值判斷是否要繼續更新。 this.setState( )方法是React.js中最常見的一種方法,利用它可以控制各種狀態變化,達到頁面各種交互效果,但是,我們在React開發中偶爾會發現,明明已經通過this.setState...
摘要:不保證這個狀態的更新是立即執行的。這個問題導致如果開發者在之后立即去訪問可能訪問的不是最新的狀態。不應該被直接更改,而是應該新建一個來表示更新后的狀態。實驗采用基于控制變量法的對照試驗。至于的問題,留給讀者自己吧。 React組件重新渲染的條件是: B.只要調用this.setState()就會發生重新渲染。 C.必須調用this.setState()且傳遞不同于當前this.setS...
摘要:我們來從設計思想上,和官方團隊的回應上,了解一下否決理由。此外,還有一個方法新的接口設計支持接收一個回調函數,當其子組件掛載時,這個回調函數就會相應觸發。 從 setState 那個眾所周知的小秘密說起... 在 React 組件中,調用 this.setState() 是最基本的場景。這個方法描述了 state 的變化、觸發了組件 re-rendering。但是,也許看似平常的 th...
摘要:我們來從設計思想上,和官方團隊的回應上,了解一下否決理由。此外,還有一個方法新的接口設計支持接收一個回調函數,當其子組件掛載時,這個回調函數就會相應觸發。 從 setState 那個眾所周知的小秘密說起... 在 React 組件中,調用 this.setState() 是最基本的場景。這個方法描述了 state 的變化、觸發了組件 re-rendering。但是,也許看似平常的 th...
摘要:異步渲染利用事件循環,延遲渲染函數的調用調用回調函數處理后跟函數的情況淺合并邏輯事件循環,關于的事件循環和的事件循環后續會單獨寫篇文章。 showImg(https://segmentfault.com/img/remote/1460000015785464?w=640&h=280); 看源碼一個痛處是會陷進理不順主干的困局中,本系列文章在實現一個 (x)react 的同時理順 Rea...
閱讀 3756·2021-08-11 11:16
閱讀 1624·2019-08-30 15:44
閱讀 1997·2019-08-29 18:45
閱讀 2270·2019-08-26 18:18
閱讀 1000·2019-08-26 13:37
閱讀 1570·2019-08-26 11:43
閱讀 2117·2019-08-26 11:34
閱讀 378·2019-08-26 10:59