国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React setState源碼實(shí)現(xiàn)理解

xietao3 / 3192人閱讀

摘要:新的值回調(diào)函數(shù)。官方注解是給組件做個(gè)標(biāo)記需要重新渲染,并且將可選的回調(diào)函數(shù)添加到函數(shù)列表中,這些函數(shù)將在重新渲染的時(shí)候執(zhí)行。一共做了兩件事一是通過執(zhí)行方法來更新組件二是若方法傳入了回調(diào)函數(shù)則將回調(diào)函數(shù)存入隊(duì)列。

Q1

setState改變狀態(tài)之后,不會(huì)立即更新state值。所以,如果改變state值,react是什么時(shí)候進(jìn)行組件的更新呢?setState()到底做了一些什么呢?

A1 1. react生命周期

2. react更新state具體做了什么

引入一段源碼

react中定義的setState方法,定義了兩個(gè)參數(shù)(partialState,callback)。

partialState: 新的state值;
callback: 回調(diào)函數(shù)。

getInternalInstanceReadyForUpdate方法的目的是獲取當(dāng)前組件對(duì)象,將其賦值給internalInstance變量。接下來判斷當(dāng)前組件對(duì)象的state更新隊(duì)列是否存在,如果存在則將partialState也就是新的state值加入隊(duì)列;如果不存在,則創(chuàng)建該對(duì)象的更新隊(duì)列。然后進(jìn)入enqueueUpdate方法。

enqueueCallback也是先獲取當(dāng)前組件對(duì)象,如果已經(jīng)存在其他回調(diào),就加入等待回調(diào)隊(duì)列,如果當(dāng)前沒有回調(diào),就創(chuàng)建等待回調(diào)隊(duì)列。然后進(jìn)入enqueueUpdate方法。

可以發(fā)現(xiàn),enqueueSetState&enqueueCallback最終都是進(jìn)入enqueueUpdate方法。下面我們來看看enqueueUpdate方法。

官方注解是:給組件做個(gè)標(biāo)記:需要重新渲染,并且將可選的回調(diào)函數(shù)添加到函數(shù)列表中,這些函數(shù)將在重新渲染的時(shí)候執(zhí)行。

我們看一下函數(shù)具體做了哪些事。發(fā)現(xiàn)這個(gè)函數(shù)只是做了一個(gè)判斷:如果batchingStrategy.isBatchingUpdates為false,就執(zhí)行batchingStrategy.batchedUpdates(enqueueUpdate,component),否則就加入dirtyComponents。

這里提到batchingStrategy,批量更新策略。

批量更新策略是什么呢?看代碼發(fā)現(xiàn)batchingStrategy批量更新策略只是一個(gè)簡(jiǎn)單的對(duì)象,定義了一個(gè) isBatchingUpdates 的布爾值和一個(gè) batchedUpdates 方法。默認(rèn)isBatchingUpdates(下面稱為更新標(biāo)志)為false,然后會(huì)進(jìn)入batchedUpdates方法,先把更新標(biāo)志isBatchingUpdates設(shè)為true,然后執(zhí)行transaction.perform(callback),即transaction.perform(enqueueUpdate)。

React內(nèi)部采用了"狀態(tài)機(jī)"的概念,組件處于不同的狀態(tài)時(shí),所執(zhí)行的邏輯也并不相同。以組件更新流程為例,React以事務(wù)+狀態(tài)的形式對(duì)組件進(jìn)行更新。

通過上面的一部分代碼,我們發(fā)現(xiàn)setState()方法主要是enqueueUpdate()進(jìn)行狀態(tài)更新,怎樣進(jìn)行狀態(tài)更新呢?定義了一個(gè)批量更新策略:判斷更新標(biāo)志isBatchingUpdates的值,如果為false,調(diào)用batchedUpdates()-->(先把更新標(biāo)志isBatchingUpdates改為true,然后調(diào)用transaction.perform(enqueueUpdate))。如果為true,就把組件加入dirtyComponents數(shù)組中。

React內(nèi)部采用了"狀態(tài)機(jī)"的概念,組件處于不同的狀態(tài)時(shí),所執(zhí)行的邏輯也并不相同。以組件更新流程為例,React以事務(wù)+狀態(tài)的形式對(duì)組件進(jìn)行更新,因此接下來我們看看事務(wù)的機(jī)制。

3. transaction 事務(wù)
                    wrappers (injected at creation time)
                                   +        +
                                   |        |
                 +-----------------|--------|--------------+
                 |                 v        |              |
                 |      +---------------+   |              |
                 |   +--|    wrapper1   |---|----+         |
                 |   |  +---------------+   v    |         |
                 |   |          +-------------+  |         |
                 |   |     +----|   wrapper2  |--------+   |
                 |   |     |    +-------------+  |     |   |
                 |   |     |                     |     |   |
                 |   v     v                     v     v   | wrapper
                 | +---+ +---+   +---------+   +---+ +---+ | invariants
perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
+----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
                 | |   | |   |   |         |   |   | |   | |
                 | |   | |   |   |         |   |   | |   | |
                 | |   | |   |   |         |   |   | |   | |
                 | +---+ +---+   +---------+   +---+ +---+ |
                 |  initialize                    close    |
                 +-----------------------------------------+

這是官方代碼的解析圖。

可以看出調(diào)用函數(shù)是perform(anyMethod),然后方法anyMethod被wrapper包裹了,wrapper依次執(zhí)行了initialize->anyMethod->close

function anyMethod(){
    console.log("xx")
};
transaction.perform(anyMethod);

代碼的執(zhí)行順序是

initialize()
輸出xx
close()

所以這里wrapper是怎樣定義的呢?

第二個(gè)wrapper比較簡(jiǎn)單,先來看一下第二個(gè)wrapper。

第二個(gè)wrapper(RESET_BATCHED_UPDATES)的作用是將更新標(biāo)志isBatchingUpdates重置為false;我的理解這里是收集完所有要更新的state值,都加入_pendingStateQueue待更新狀態(tài)隊(duì)列了,然后組件更新完了之后,將更新標(biāo)志重置為false,等待下次更新。然后下面來看一下第一個(gè)wrapper。


5&f=png&s=54081)

第一個(gè)wrapper主要的作用是更新組件,執(zhí)行了ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)。

可以看到flushBatchedUpdates方法循環(huán)遍歷所有的dirtyComponents,又通過事務(wù)的形式調(diào)用runBatchedUpdates方法。

一共做了兩件事:

一是通過執(zhí)行updateComponent方法來更新組件

二是若setState方法傳入了回調(diào)函數(shù)則將回調(diào)函數(shù)存入callbackQueue隊(duì)列。

然后看一下updateComponent方法,官方注釋是:更新組件,會(huì)調(diào)用shouldComponentUpdate,然后調(diào)用剩余的生命周期函數(shù),更新DOM結(jié)構(gòu)

這里終于更新了組件。看代碼會(huì)發(fā)現(xiàn)在shouldComponentUpdate之前,執(zhí)行了_processPendingState方法,該方法主要對(duì)state進(jìn)行處理:

1.如果更新隊(duì)列為null,那么返回原來的state;

2.如果更新隊(duì)列有一個(gè)更新,那么返回更新值;

3.如果更新隊(duì)列有多個(gè)更新,那么通過for循環(huán)將它們合并;

綜上說明了,在一個(gè)生命周期內(nèi),在componentShouldUpdate執(zhí)行之前,所有的state變化都會(huì)被合并,最后統(tǒng)一處理。

4. 回顧上述問題

綜上,

setState()為啥沒有立即更新this.state值呢

如果在componentDidMount()中連續(xù)多次setState,無法進(jìn)行state累加呢

批量更新策略isBatchingStrategy干了什么,怎么做到更新的呢

那按照上述說的批量更新,第一次setState-->進(jìn)入enqueueUpdate()-->此時(shí)isBatchingUpdates默認(rèn)為false-->batchedUpdates(enqueueUpdate,...)-->設(shè)置isBatchingUpdates為true;transaction.perform(enqueueUpdates);-->(第一個(gè)wrapper:FLUSH_BATCHED_UPDATES)組件更新-->(第二個(gè)wrapper:RESET_BATCHED_UPDATES的close方法)設(shè)置isBatchingUpdates為false-->第二次setState-->isBatchingUpdates為false-->..-->組件更新-->isBatchingUpdates恢復(fù)為false。

這樣和結(jié)果不對(duì)呀?按上述邏輯的話,豈不是每次setState都會(huì)更新this.state的值?

調(diào)試代碼會(huì)發(fā)現(xiàn),原來整個(gè)將 React 組件渲染到 DOM 中的過程就處于一個(gè)大的 Transaction 中。

在進(jìn)入生命周期之前,就會(huì)調(diào)用batchedUpdates(),所以此時(shí)isBatchingUpdates已經(jīng)修改為true了。后面第一次進(jìn)入setState()時(shí),就會(huì)進(jìn)入加入dirtyComponent中。所以這也就是為什么兩次打印 this.state.foods 都是 "" 的原因,新的 state 還沒有被應(yīng)用到組件中。

5. 總結(jié)

setState(partialState, callback),不會(huì)立即更新state值,要合并所有的state變化后,然后重新渲染的時(shí)候,state值才會(huì)更新。

setState(partialState, callback): callback會(huì)在所有狀態(tài)更新之后再調(diào)用(demo中state的foods&drinks全部更新之后才會(huì)調(diào)用)

事務(wù)這么有用,那我們可以調(diào)用事務(wù)嗎?答案是不可以。

另外在componentWillMount里面setState()不會(huì)觸發(fā)重新渲染

Q2

在render函數(shù)里,無法setState

A2

在render函數(shù)中不能setState()。

從react生命周期可以看出:state更新會(huì)重新觸發(fā)render(),所以會(huì)導(dǎo)致setState()-->re-render()-->setState()--re-render()-->...-->setState()-->re-render(),一直循環(huán)往復(fù)。

所以,同理在state更新的生命周期的函數(shù)中(componentWillUpdate/componentDidUpdate),都不能setState()

參考資料

https://juejin.im/post/59cc4c...

https://zh-hans.reactjs.org/d...

https://www.imooc.com/article...

https://segmentfault.com/a/11...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105097.html

相關(guān)文章

  • 理解 React 輕量狀態(tài)管理庫 Unstated

    摘要:返回,用來包裹頂層組件,向應(yīng)用中注入狀態(tài)管理實(shí)例,可做數(shù)據(jù)的初始化。方法返回創(chuàng)建的狀態(tài)管理實(shí)例,作為參數(shù)傳遞給調(diào)用的函數(shù),函數(shù)拿到實(shí)例,操作或顯示數(shù)據(jù)。用來實(shí)現(xiàn)一個(gè)狀態(tài)管理類。為中的狀態(tài)管理實(shí)例數(shù)據(jù)。 個(gè)人網(wǎng)站: https://www.neroht.com 在React寫應(yīng)用的時(shí)候,難免遇到跨組件通信的問題。現(xiàn)在已經(jīng)有很多的解決方案。 React本身的Context Redux結(jié)合...

    Profeel 評(píng)論0 收藏0
  • setState promise 化的探討 體會(huì) React 團(tuán)隊(duì)設(shè)計(jì)思想

    摘要:我們來從設(shè)計(jì)思想上,和官方團(tuán)隊(duì)的回應(yīng)上,了解一下否決理由。此外,還有一個(gè)方法新的接口設(shè)計(jì)支持接收一個(gè)回調(diào)函數(shù),當(dāng)其子組件掛載時(shí),這個(gè)回調(diào)函數(shù)就會(huì)相應(yīng)觸發(fā)。 從 setState 那個(gè)眾所周知的小秘密說起... 在 React 組件中,調(diào)用 this.setState() 是最基本的場(chǎng)景。這個(gè)方法描述了 state 的變化、觸發(fā)了組件 re-rendering。但是,也許看似平常的 th...

    caiyongji 評(píng)論0 收藏0
  • setState promise 化的探討 體會(huì) React 團(tuán)隊(duì)設(shè)計(jì)思想

    摘要:我們來從設(shè)計(jì)思想上,和官方團(tuán)隊(duì)的回應(yīng)上,了解一下否決理由。此外,還有一個(gè)方法新的接口設(shè)計(jì)支持接收一個(gè)回調(diào)函數(shù),當(dāng)其子組件掛載時(shí),這個(gè)回調(diào)函數(shù)就會(huì)相應(yīng)觸發(fā)。 從 setState 那個(gè)眾所周知的小秘密說起... 在 React 組件中,調(diào)用 this.setState() 是最基本的場(chǎng)景。這個(gè)方法描述了 state 的變化、觸發(fā)了組件 re-rendering。但是,也許看似平常的 th...

    forrest23 評(píng)論0 收藏0
  • 深入理解react

    摘要:最近在看源碼,發(fā)覺以前對(duì)的理解實(shí)在浮淺,這里記錄了一些以前疏忽的點(diǎn)。和在里面,經(jīng)過的解析后,會(huì)變成執(zhí)行后的結(jié)果。原來對(duì)的理解就是類似這種寫法,現(xiàn)在看了實(shí)現(xiàn)之后才理解。 最近在看react源碼,發(fā)覺以前對(duì)react的理解實(shí)在浮淺,這里記錄了一些以前疏忽的點(diǎn)。 createElement和component 在react里面,經(jīng)過babel的解析后,jsx會(huì)變成createElement執(zhí)...

    CoderStudy 評(píng)論0 收藏0
  • Component,PureComponent源碼解析

    摘要:首先是創(chuàng)建了一個(gè)構(gòu)造函數(shù),他的原型指到的原型然后創(chuàng)建了一個(gè)加上了和一樣的屬性這里為啥不用。的原型指向的實(shí)例修改原型的屬性使其正確指向的構(gòu)造函數(shù),并掛一個(gè)的屬性。 每次都信誓旦旦的給自己立下要好好學(xué)習(xí)react源碼的flag,結(jié)果都是因?yàn)槟硞€(gè)地方卡住了,或是其他原因沒看多少就放棄了。這次又給自己立個(gè)flag-堅(jiān)持看完react源碼。為了敦促自己,特開設(shè)這樣一個(gè)專欄來記錄自己的學(xué)習(xí)歷程,這...

    luqiuwen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<