摘要:下面來逐步的解析圖里的流程。一將事務放進隊列中這里的可以傳也可以傳它會產生新的以一種的方式跟舊的進行合并。如果當前不在更新過程的話,則執行更新事務。以上即為的實現過程,最后還是用一個流程圖在做一個總結吧參考文檔
前言
學過react的人都知道,setState在react里是一個很重要的方法,使用它可以更新我們數據的狀態,本篇文章從簡單使用到深入到setState的內部,全方位為你揭開setState的神秘面紗~
setState的使用注意事項setState(updater, callback)這個方法是用來告訴react組件數據有更新,有可能需要重新渲染。它是異步的,react通常會集齊一批需要更新的組件,然后一次性更新來保證渲染的性能,所以這就給我們埋了一個坑:
那就是在使用setState改變狀態之后,立刻通過this.state去拿最新的狀態往往是拿不到的。
要點一所以第一個使用要點就是:如果你需要基于最新的state做業務的話,可以在componentDidUpdate或者setState的回調函數里獲取。(注:官方推薦第一種做法)
// setState回調函數 changeTitle: function (event) { this.setState({ title: event.target.value }, () => this.APICallFunction()); }, APICallFunction: function () { // Call API with the updated value }要點二
設想有一個需求,需要在在onClick里累加兩次,如下
onClick = () => { this.setState({ index: this.state.index + 1 }); this.setState({ index: this.state.index + 1 }); }
在react眼中,這個方法最終會變成
Object.assign( previousState, {index: state.index+ 1}, {index: state.index+ 1}, ... )
由于后面的數據會覆蓋前面的更改,所以最終只加了一次.所以如果是下一個state依賴前一個state的話,推薦給setState傳function
onClick = () => { this.setState((prevState, props) => { return {quantity: prevState.quantity + 1}; }); this.setState((prevState, props) => { return {quantity: prevState.quantity + 1}; }); }
以上是使用setState的兩個注意事項,接下來我們來看看setState被調用之后,更新組件的過程,下面是一個簡單的流程圖。
下面來逐步的解析圖里的流程。
一、setState ReactBaseClassses.jsReactComponent.prototype.setState = function (partialState, callback) { // 將setState事務放進隊列中 this.updater.enqueueSetState(this, partialState); if (callback) { this.updater.enqueueCallback(this, callback, "setState"); } };
這里的partialState可以傳object,也可以傳function,它會產生新的state以一種Object.assgine()的方式跟舊的state進行合并。
二、enqueueSetStateenqueueSetState: function (publicInstance, partialState) { // 獲取當前組件的instance var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, "setState"); // 將要更新的state放入一個數組里 var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []); queue.push(partialState); // 將要更新的component instance也放在一個隊列里 enqueueUpdate(internalInstance); }
這段代碼可以得知,enqueueSetState 做了兩件事:
1、將新的state放進數組里
2、用enqueueUpdate來處理將要更新的實例對象
function enqueueUpdate(component) { // 如果沒有處于批量創建/更新組件的階段,則處理update state事務 if (!batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component); return; } // 如果正處于批量創建/更新組件的過程,將當前的組件放在dirtyComponents數組中 dirtyComponents.push(component); }
由這段代碼可以看到,當前如果正處于創建/更新組件的過程,就不會立刻去更新組件,而是先把當前的組件放在dirtyComponent里,所以不是每一次的setState都會更新組件~。
這段代碼就解釋了我們常常聽說的:setState是一個異步的過程,它會集齊一批需要更新的組件然后一起更新。
而batchingStrategy 又是個什么東西呢?
四、batchingStrategy ReactDefaultBatchingStrategy.jsvar ReactDefaultBatchingStrategy = { // 用于標記當前是否出于批量更新 isBatchingUpdates: false, // 當調用這個方法時,正式開始批量更新 batchedUpdates: function (callback, a, b, c, d, e) { var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates; ReactDefaultBatchingStrategy.isBatchingUpdates = true; // 如果當前事務正在更新過程在中,則調用callback,既enqueueUpdate if (alreadyBatchingUpdates) { return callback(a, b, c, d, e); } else { // 否則執行更新事務 return transaction.perform(callback, null, a, b, c, d, e); } } };
這里注意兩點:
1、如果當前事務正在更新過程中,則使用enqueueUpdate將當前組件放在dirtyComponent里。
2、如果當前不在更新過程的話,則執行更新事務。
/** ** wrappers (injected at creation time) * + + * | | * +-----------------|--------|--------------+ * | v | | * | +---------------+ | | * | +--| wrapper1 |---|----+ | * | | +---------------+ v | | * | | +-------------+ | | * | | +----| wrapper2 |--------+ | * | | | +-------------+ | | | * | | | | | | * | v v v v | wrapper * | +---+ +---+ +---------+ +---+ +---+ | invariants * perform(anyMethod) | | | | | | | | | | | | maintained * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|--------> * | | | | | | | | | | | | * | | | | | | | | | | | | * | | | | | | | | | | | | * | +---+ +---+ +---------+ +---+ +---+ | * | initialize close | * +-----------------------------------------+ **/
簡單說明一下transaction對象,它暴露了一個perform的方法,用來執行anyMethod,在anyMethod執行的前,需要先執行所有wrapper的initialize方法,在執行完后,要執行所有wrapper的close方法,就辣么簡單。
在ReactDefaultBatchingStrategy.js,tranction 的 wrapper有兩個 FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES
var RESET_BATCHED_UPDATES = { initialize: emptyFunction, close: function () { ReactDefaultBatchingStrategy.isBatchingUpdates = false; } }; var FLUSH_BATCHED_UPDATES = { initialize: emptyFunction, close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates) }; var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
可以看到,這兩個wrapper的initialize都沒有做什么事情,但是在callback執行完之后,RESET_BATCHED_UPDATES 的作用是將isBatchingUpdates置為false,
FLUSH_BATCHED_UPDATES 的作用是執行flushBatchedUpdates,然后里面會循環所有dirtyComponent,調用updateComponent來執行所有的生命周期方法,componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate 最后實現組件的更新。
以上即為setState的實現過程,最后還是用一個流程圖在做一個總結吧~
參考文檔:
https://zhuanlan.zhihu.com/p/...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107937.html
摘要:當轉換后的原始數據類型為類型或者類型,則繼續轉換成類型。具體流程圖如下備注的數據類型可以分為以下兩種原始數據類型才引入的引用類型類型類型轉換成類型的規則類型類型標準的數字格式如果是標準的數字格式,轉換成類型相比不用多說,比如下面這幾個栗子 拋磚引玉 按照正常的邏輯來說,我們判斷兩個值是否相等會遵循以下規則:showImg(https://segmentfault.com/img/rem...
摘要:所以,我們這個小游戲發布以后,我們就開始花了很多很多時間來打擊外掛。二距離判斷像素點判斷該方法采用自目前最火的跳一跳小游戲輔助程序。 作者:Hahn, 騰訊高級UI工程師商業轉載請聯系騰訊WeTest獲得授權,非商業轉載請注明出處。 原文鏈接:http://wetest.qq.com/lab/view/364.html WeTest 導讀 張小龍:這個游戲發布以后,其實它的效果有點超...
摘要:是事件回調,有時機執行邏輯,所以為,,是合并的,結束之后被重新設置為。沒有控制權的情況有很多回調,網絡回調等等。的說明從函數名上理解強制更新。所以可以簡單的理解為,只不過這個是不調用自己的聲明周期的。 setState同步異步問題,React批量更新一直是一個比較模糊的問題,本文希望從框架設計的角度說明一下這個問題。 React有個UI = f(data) 公式:UI是由data推導...
摘要:我們來從設計思想上,和官方團隊的回應上,了解一下否決理由。此外,還有一個方法新的接口設計支持接收一個回調函數,當其子組件掛載時,這個回調函數就會相應觸發。 從 setState 那個眾所周知的小秘密說起... 在 React 組件中,調用 this.setState() 是最基本的場景。這個方法描述了 state 的變化、觸發了組件 re-rendering。但是,也許看似平常的 th...
摘要:我們來從設計思想上,和官方團隊的回應上,了解一下否決理由。此外,還有一個方法新的接口設計支持接收一個回調函數,當其子組件掛載時,這個回調函數就會相應觸發。 從 setState 那個眾所周知的小秘密說起... 在 React 組件中,調用 this.setState() 是最基本的場景。這個方法描述了 state 的變化、觸發了組件 re-rendering。但是,也許看似平常的 th...
閱讀 2104·2023-05-11 16:55
閱讀 3504·2021-08-10 09:43
閱讀 2618·2019-08-30 15:44
閱讀 2440·2019-08-29 16:39
閱讀 583·2019-08-29 13:46
閱讀 2005·2019-08-29 13:29
閱讀 921·2019-08-29 13:05
閱讀 691·2019-08-26 13:51