成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

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

xietao3 / 3252人閱讀

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

Q1

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

A1 1. react生命周期

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

引入一段源碼

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

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

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

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

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

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

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

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

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

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

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

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

3. transaction 事務
                    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是怎樣定義的呢?

第二個wrapper比較簡單,先來看一下第二個wrapper。

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


5&f=png&s=54081)

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

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

一共做了兩件事:

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

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

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

這里終于更新了組件??创a會發(fā)現(xiàn)在shouldComponentUpdate之前,執(zhí)行了_processPendingState方法,該方法主要對state進行處理:

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

2.如果更新隊列有一個更新,那么返回更新值;

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

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

4. 回顧上述問題

綜上,

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

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

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

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

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

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

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

5. 總結

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

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

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

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

Q2

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

A2

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

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

所以,同理在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...

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/105097.html

相關文章

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

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

    Profeel 評論0 收藏0
  • setState promise 化的探討 體會 React 團隊設計思想

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

    caiyongji 評論0 收藏0
  • setState promise 化的探討 體會 React 團隊設計思想

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

    forrest23 評論0 收藏0
  • 深入理解react

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

    CoderStudy 評論0 收藏0
  • Component,PureComponent源碼解析

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

    luqiuwen 評論0 收藏0

發(fā)表評論

0條評論

xietao3

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<