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