【Under-the-hood-ReactJS-Part13】React原始碼解讀

越山發表於2018-07-05

接上文,

React流程圖:
https://bogdan-lyashenko.gith…

如果元件真的需要更新

在元件剛開始更新過程時,如果有定義componentWillUpdate方法,則會進行呼叫。之後,會重繪元件並將對於componentDidUpdate方法的呼叫壓入佇列(React會延遲這個方法的呼叫,因為這個方法需要在更新過程的最後被呼叫)。
對於重繪過程,就是呼叫元件的render方法,然後根據返回值更新DOM。具體過程如下,第一步,呼叫元件例項(ExampleApplication)的render方法然後將結果儲存下來(呼叫render方法會返回React元素)。接著,將返回的元素和之前的進行比較的,以驗證DOM是否真的需要更新。

上面的過程是不是很熟悉?沒錯,這個就是React的看家本領了,虛擬DOM,避免對於DOM的無用更新,提高了整個React的效能。看下程式碼裡對shouldUpdateReactComponent的註釋:

決定當前的例項是否需要更新,或者銷燬然後用新的例項替換

大致說來,這個方法就是用來檢測當前元素是否需要被完全替換,換句話說,老的元素應該首先被解除安裝,然後,新元素(render方法的返回)應該被掛載並做標記,然後接收到的mount方法的返回值,應該會被用於替換當前DOM上的元素,或者,如果元素只需要部分更新,那就按需進行更新。當以下場景發生時,通常是需要完全替換元素的:新元素不包含任何東西(在render方法裡被移除了)或者元素型別完全不同。比如,原先是div,但是現在變成了其他標籤。我們看下程式碼,程式碼比較簡單:

///src/renderers/shared/shared/shouldUpdateReactComponent.js#25

function shouldUpdateReactComponent(prevElement, nextElement) {
    var prevEmpty = prevElement === null || prevElement === false;
    var nextEmpty = nextElement === null || nextElement === false;
    if (prevEmpty || nextEmpty) {
        return prevEmpty === nextEmpty;
    }

    var prevType = typeof prevElement;
    var nextType = typeof nextElement;
    if (prevType === `string` || prevType === `number`) {
        return (nextType === `string` || nextType === `number`);
    } else {
        return (
            nextType === `object` &&
            prevElement.type === nextElement.type &&
            prevElement.key === nextElement.key
        );
    }
}

好,對應於我們的ExampleApplication這個列子,我們對於state方法的更改並不會對render方法造成影響。所以我們進入下一步,也就是對於DOM節點的更新。
(未完待續)

相關文章