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

資訊專欄INFORMATION COLUMN

深入React知識點整理(二)

villainhr / 480人閱讀

摘要:承接上文,深入知識點整理一使用也滿一年了,從剛剛會使用到逐漸探究其底層實現,以便學習幾招奇技淫巧從而在自己的代碼中使用,寫出高效的代碼。有限狀態機,表示有限個狀態以及在這些狀態之間的轉移和動作等行為的模型。

承接上文,深入React知識點整理(一)
使用React也滿一年了,從剛剛會使用到逐漸探究其底層實現,以便學習幾招奇技淫巧從而在自己的代碼中使用,寫出高效的代碼。下面整理一些知識點,算是React看書,使用,感悟的一些總結:

React 生命周期

setState調用棧

7.React 生命周期
React 的主要思想是通過構建可復用組件來構建用戶界面。所謂組件,其實就是有限狀態機(FSM),通過狀態渲染對應的界面,且每個組件都有自己的生命周期,它規定了組件的狀態和方法需要在哪個階段改變和執行。

有限狀態機,表示有限個狀態以及在這些狀態之間的轉移和動作等行為的模型。一般通過狀態、事件、轉換和動作來描述有限狀態機。

組件的生命周期在不同狀態下的執行順序:

當首次掛載組件時,按順序執行 getDefaultPropsgetInitialStatecomponentWillMountrendercomponentDidMount

當卸載組件時,執行 componentWillUnmount

當重新掛載組件時,此時按順序執行 getInitialStatecomponentWillMountrendercomponentDidMount,但并不執行 getDefaultProps

當再次渲染組件時,組件接受到更新狀態,此時按順序執行 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate

constructor 中的 this.state = {} 其實就是調用內部的 getInitialState 方法。

自定義組件(ReactCompositeComponent)的生命周期主要通過 3 個階段進行管理——MOUNTING、RECEIVE_PROPS 和 UNMOUNTING,它們負責通知組件當前所處的階段,應該執行生命周期中的哪個步驟。

創建組件:createClass或者extend Component創建自定義組件,初始化defaultProps。

MOUNTING:調用getInitialState初始化state,調用componentWillMount,之后render,最后調用componentDidMount。通過 mountComponent 掛載組件,初始化序號、標記等參數,判斷是否為無狀態組件,并進行對應的組件初始化工作,比如初始化 propscontext 等參數。利用 getInitialState 獲取初始化state、初始化更新隊列和更新狀態。

RECEIVE_PROPS:當參數變化的時候,按照圖中順序調用,且在 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdate中也還是無法獲取到更新后的 this.state,即此時訪問的 this.state 仍然是未更新的數據。updateComponent 本質上也是通過遞歸渲染內容的,由于遞歸的特性,父組件的 componentWillUpdate是在其子組件的 componentWillUpdate 之前調用的,而父組件的 componentDidUpdate也是在其子組件的 componentDidUpdate 之后調用的。

UNMOUNTING:如果存在 componentWillUnmount,則執行并重置所有相關參數、更新隊列以及更新狀態,如果此時在 componentWillUnmount 中調用 setState,是不會觸發 re-render 的,這是因為所有更新
隊列和更新狀態都被重置為 null,并清除了公共類,完成了組件卸載操作。

最后,一張圖歸納React生命周期,以及不同生命周期中setState的使用情況:
屏幕快照 2017-12-14 下午10.42.31.png

這里主要介紹了React生命周期執行順序,以及在不同生命周期內使用setState的情況,重點在于合適使用setState。

8.setState調用棧

React中的setState是個很著名的方法,當你需要更改state觸發頁面重繪的時候,調用setSatet方法。但是setState并不會立刻執行你的更改,這也是剛開始使用React時很苦惱的一件事。

經過一段時間的使用和學習,知道了React的setState是"異步"的:

State Updates May Be Asynchronous

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

官方給出的回答是React為了優化性能,會合并多次setState操作,并計算出最終值再執行,所以setState看起來是"異步"的。這種想法很好,我們可以借鑒到項目開發中去,但是代碼層面是如何實現的?在任何地方調用setState都會是’異步的嗎‘?

setState源碼:

// 更新 state
ReactComponent.prototype.setState = function (partialState, callback) {
    this.updater.enqueueSetState(this, partialState);
    if (callback) {
        this.updater.enqueueCallback(this, callback, "setState");
    }
};
...
enqueueSetState: function (publicInstance, partialState) {
    var internalInstance = getInternalInstanceReadyForUpdate(
        publicInstance,
        "setState"
    );
    if (!internalInstance) {
        return;
    }
    // 更新隊列合并操作
    var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
    queue.push(partialState);
    enqueueUpdate(internalInstance);
},
...
// 如果存在 _pendingElement、_pendingStateQueue和_pendingForceUpdate,則更新組件
performUpdateIfNecessary: function (transaction) {
    if (this._pendingElement != null) {
        ReactReconciler.receiveComponent(this, this._pendingElement, transaction, this._context);
    }
    if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
        this.updateComponent(transaction, this._currentElement, this._currentElement, this._context,
            this._context);
    }
} 

通過上面源碼大致可以看出,setState函數執行的時候,把被更新的state放入到_pendingStateQuenue隊列中,之后將組件實例傳入并執行enqueueUpdate,并且如果有回調函數放到enqueueCallback中。

問題現在全在enqueueUpdate上,通過簡易的流程圖可以看出enqueueUpdate判斷當前組件是否處于批量更新模式中,是就簡單將組件存入臟組件隊列,不是的話更新臟組件隊列,從而更新調用updateComponent,更新props和state,觸發頁面重繪。
屏幕快照 2017-12-07 下午7.46.18.png

到這里可以看到很清楚地看到,setState并不是全部都是’異步的‘,當組件處于非批量更新模式的時候,是立即更新的。enqueueUpdate源碼:

function enqueueUpdate(component) {
    ensureInjected();
    // 如果不處于批量更新模式
    if (!batchingStrategy.isBatchingUpdates) {
        batchingStrategy.batchedUpdates(enqueueUpdate, component);
        return;
    }
    // 如果處于批量更新模式,則將該組件保存在 dirtyComponents 中
    dirtyComponents.push(component);
} 

batchingStrategy代碼如下:

var ReactDefaultBatchingStrategy = {
    isBatchingUpdates: false,
    batchedUpdates: function(callback, a, b, c, d, e) {
        var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
        ReactDefaultBatchingStrategy.isBatchingUpdates = true;
        if (alreadyBatchingUpdates) {
            callback(a, b, c, d, e);
        } else {
            transaction.perform(callback, null, a, b, c, d, e);
        }
    },
} 

通過代碼來看,isBatchingUpdates默認是false,也就是組件默認是不處于批量更新模式的,第一次執行enqueueUpdate時候,在batchedUpdates方法中,將開關置true,之后更新都處于批量更新模式。

這里還有一個概念:事務。

事務就是將需要執行的方法使用 wrapper 封裝起來,再通過事務提供的 perform 方法執行。而在 perform 之前,先執行所有 wrapper 中的 initialize 方法,執行完 perform 之后(即執行method 方法后)再執行所有的 close 方法。一組 initialize 及 close 方法稱為一個 wrapper。從圖3-16中可以看出,事務支持多個 wrapper 疊加。

屏幕快照 2017-12-07 下午8.28.26.png

那事務又跟setState有什么關系,我們舉個例子:

import React, { Component } from "react";
class Example extends Component {
    constructor() {
        super();
        this.state = {
            val: 0
        };
    }
    componentDidMount() {
        this.setState({val: this.state.val + 1});
        console.log(this.state.val); // 第 1 次輸出
        this.setState({val: this.state.val + 1});
        console.log(this.state.val); // 第 2 次輸出
        setTimeout(() => {
            this.setState({val: this.state.val + 1});
            console.log(this.state.val); // 第 3 次輸出
            this.setState({val: this.state.val + 1});
            console.log(this.state.val); // 第 4 次輸出
        }, 0);
    }
    render() {
        return null;
    }
} 

這個例子中,componentDidMount生命周期函數中連著調用了兩次setState,之后在setState中又連著調用了兩次,結果卻完全不同,打印輸出0,0,2,3。嘗試著在React的各個階段函數中打印log結果如下:

屏幕快照 2017-12-07 下午9.20.54.png

通過截圖可以看到,我們在調用setState的之后,打印輸出了事務結束的closeAll,這說明componentDidMount函數被事務當做method調用,之后才打印輸出batchedUpdates。原來早在 setState 調用前,已經處于batchedUpdates 執行的事務中了。那這次 batchedUpdate 方法,又是誰調用的呢?讓我們往前再追溯一層,原來是 ReactMount.js中的 _renderNewRootComponent 方法。也就是說,整個將 React 組件渲染到 DOM 中的過程就處于一個大的事務中。

接下來的解釋就順理成章了,因為在 componentDidMount 中調用 setState 時,batchingStrategy的 isBatchingUpdates 已經被設為 true,所以兩次 setState 的結果并沒有立即生效,而是被放進了 dirtyComponents 中。這也解釋了兩次打印 this.state.val 都是 0 的原因,因為新的 state 還沒有被應用到組件中。而setTimeout函數中的setState并沒有在事務中,所以立即執行。

所以這里得到一個結論:在React中,如果是由React引發的事件處理(比如通過onClick引發的事件處理),調用setState不會同步更新this.state,除此之外的setState調用會同步執行this.state

React引發的事件處理有很多,都是我們常用的比如所有的生命周期函數(在生命周期函數中可以使用setState的),React代理的事件;這些函數應用場景很高,讓我們誤以為setState一直是"異步"的。

所以,我們也可以得出解決setState異步的方法:

使用setState第二個參數callback;

setTimeout函數(雖然不好,但也不失為一種辦法);

在componentDidUpdate處理一些邏輯(要看應用場景);

第一個參數傳入計算函數;

當然了,還有一個比較決絕的辦法,就是不用setState。

相關文章可以看看程墨老師的文章:setState為什么不會同步更新組件狀態。

總結

React算是一個顛覆式的UI框架,有很多知識點值得學習,深入的研究一些問題對于實際使用上也會有一定幫助。本文也是根據《深入React技術棧》前幾章內容摘錄,整理的知識點,有興趣可以看看原著。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92139.html

相關文章

  • Record 前端開發知識整理分享

    showImg(https://segmentfault.com/img/remote/1460000018716142?w=200&h=200); showImg(https://segmentfault.com/img/remote/1460000018716143);showImg(https://segmentfault.com/img/remote/1460000010953710);...

    TZLLOG 評論0 收藏0
  • 寫一本關于 React.js 的小書

    摘要:因為工作中一直在使用,也一直以來想總結一下自己關于的一些知識經驗。于是把一些想法慢慢整理書寫下來,做成一本開源免費專業簡單的入門級別的小書,提供給社區。本書的后續可能會做成視頻版本,敬請期待。本作品采用署名禁止演繹國際許可協議進行許可 React.js 小書 本文作者:胡子大哈本文原文:React.js 小書 轉載請注明出處,保留原文鏈接以及作者信息 在線閱讀:http://huzi...

    Scorpion 評論0 收藏0
  • 深入React識點整理(一)

    摘要:以我自己的理解,函數式編程就是以函數為中心,將大段過程拆成一個個函數,組合嵌套使用。越來越多的跡象表明,函數式編程已經不再是學術界的最愛,開始大踏步地在業界投入實用。也許繼面向對象編程之后,函數式編程會成為下一個編程的主流范式。 使用React也滿一年了,從剛剛會使用到逐漸探究其底層實現,以便學習幾招奇技淫巧從而在自己的代碼中使用,寫出高效的代碼。下面整理一些知識點,算是React看書...

    Gilbertat 評論0 收藏0
  • 前端資源系列(4)-前端學習資源分享&前端面試資源匯總

    摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...

    princekin 評論0 收藏0
  • 前端文檔收集

    摘要:系列種優化頁面加載速度的方法隨筆分類中個最重要的技術點常用整理網頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數組函數數據訪問性能優化方案實現的大排序算法一怪對象常用方法函數收集數組的操作面向對象和原型繼承中關鍵詞的優雅解釋淺談系列 H5系列 10種優化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術點 常用meta整理 網頁性能管理詳解 HTML5 ...

    jsbintask 評論0 收藏0

發表評論

0條評論

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