Heim >Web-Frontend >js-Tutorial >Analyse des ersten Renderings von React (reines DOM-Element)

Analyse des ersten Renderings von React (reines DOM-Element)

不言
不言nach vorne
2018-10-20 14:38:002693Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Analyse des ersten Renderings von React (reine DOM-Elemente). Ich hoffe, dass er für Sie hilfreich ist.

React ist eine sehr große Bibliothek, da ReactDom und ReactNative gleichzeitig berücksichtigt werden müssen, ebenso wie Server-Rendering usw., der Code weist einen hohen Abstraktionsgrad und eine sehr tiefe Verschachtelungsebene auf Der Quellcode ist sehr schwierig. Beim Erlernen des React-Quellcodes hat mir diese Artikelserie am meisten geholfen, daher habe ich beschlossen, auf der Grundlage dieser Artikelserie über mein Verständnis zu sprechen. In diesem Artikel werden viele Beispiele aus dem Originaltext verwendet. Wenn Sie das ursprüngliche Gefühl erleben möchten, wird empfohlen, den Originaltext zu lesen.

Diese Artikelserie basiert auf React 15.4.2.

  • React.createElement

Wenn wir React-Projekte schreiben, schreiben wir sie normalerweise direkt in JSX-Form, und JSX wird schließlich von Babel kompiliert , wird das HTML-Tag in die Funktionsform von React.createElement konvertiert. Wenn Sie ein tieferes Verständnis haben möchten, können Sie diesen Artikel lesen, den ich zuvor geschrieben habe: Virtuelles DOM, das Sie nicht kennen (1): Einführung in virtuelles Dom. Die h-Funktion im Artikel ist standardmäßig React.createElement, wenn sie nicht in Babel konfiguriert ist.

Im Folgenden werfen wir einen Blick darauf, wie React anhand des einfachsten Beispiels gerendert wird

ReactDOM.render(
    <h1>hello world</h1>,
    document.getElementById('root')
);

Nach der JSX-Kompilierung wird es so aussehen

ReactDOM.render(
    React.createElement(
        'h1',
        { style: { "color": "blue" } },
        'hello world'
    ),
    document.getElementById('root')
);

Wer zuerst kommt, schaut es euch an der Quellcode von React.createElement.

// 文件位置:src/isomorphic/React.js

var ReactElement = require('ReactElement');

...

var createElement = ReactElement.createElement;

...

var React = {
    ...
    
    createElement: createElement,
    
    ...
}

module.exports = React;

Die endgültige Implementierung muss angesehen werden ReactElement.createElement:

// 文件位置:src/isomorphic/classic/element/ReactElement.js

ReactElement.createElement = function (type, config, children) {
    ...

    // 1. 将过滤后的有效的属性,从config拷贝到props
    if (config != null) {
        
        ...
        
        for (propName in config) {
            if (hasOwnProperty.call(config, propName) &&
                !RESERVED_PROPS.hasOwnProperty(propName)) {
                props[propName] = config[propName];
            }
        }
    }

    // 2. 将children以数组的形式拷贝到props.children属性
    var childrenLength = arguments.length - 2;
    if (childrenLength === 1) {
        props.children = children;
    } else if (childrenLength > 1) {
        var childArray = Array(childrenLength);
        for (var i = 0; i <p> führt im Wesentlichen nur drei Dinge aus: </p><ol class=" list-paddingleft-2">
<li><p> filtert die gültigen Attribute und kopiert sie von config zu props</p></li>
<li><p>Kinder in das props.children-Attribut in Form eines Arrays kopieren</p></li>
<li><p>Standardattributzuweisung</p></li>
</ol> ist <p>. Werfen wir einen Blick darauf, was es tut<code>ReactElement</code></p><pre class="brush:php;toolbar:false">// 文件位置:src/isomorphic/classic/element/ReactElement.js

var ReactElement = function (type, key, ref, self, source, owner, props) {
    var element = {
        // This tag allow us to uniquely identify this as a React Element
        $$typeof: REACT_ELEMENT_TYPE,

        // Built-in properties that belong on the element
        type: type,
        key: key,
        ref: ref,
        props: props,

        // Record the component responsible for creating this element.
        _owner: owner,
    };
    
    ...

    return element;
};
Am Ende gibt es nur ein einfaches Objekt zurück. Der Aufrufstapel sieht so aus:

React.createElement
|=ReactElement.createElement(type, config, children)
    |-ReactElement(type,..., props)
Das hier generierte ReactElement heißt

und wird als Parameter an ReactDom.render übergeben. ReactElement[1]

  • ReactDom.render

ReactDom.render wird schließlich ReactMounts _renderSubtreeIntoContainer aufrufen:

// 文件位置:src/renderers/dom/client/ReactMount.js

_renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
    ...
    var nextWrappedElement = React.createElement(
        TopLevelWrapper, 
        {
            child: nextElement
        }
    );

    ...
    
    var component = ReactMount._renderNewRootComponent(
        nextWrappedElement,
        container,
        shouldReuseMarkup,
        nextContext
    )._renderedComponent.getPublicInstance();
    
    ...
    
    return component;
},

...

var TopLevelWrapper = function () {
    this.rootID = topLevelRootCounter++;
};

TopLevelWrapper.prototype.isReactComponent = {};

TopLevelWrapper.prototype.render = function () {
    return this.props.child;
};

TopLevelWrapper.isReactTopLevelWrapper = true;

...

_renderNewRootComponent: function (
    nextElement,
    container,
    shouldReuseMarkup,
    context
) {
    ...
    
    var componentInstance = instantiateReactComponent(nextElement, false);

    ...

    return componentInstance;
},
Hier wird es wieder Another genannt Datei instanziiertReactComponent:

// 文件位置:src/renders/shared/stack/reconciler/instantiateReactComponent.js

function instantiateReactComponent(node, shouldHaveDebugID) {
    var instance;

    ...

    instance = new ReactCompositeComponentWrapper(element);
    
    ...

    return instance;
}

// To avoid a cyclic dependency, we create the final class in this module
var ReactCompositeComponentWrapper = function (element) {
    this.construct(element);
};

Object.assign(
    ReactCompositeComponentWrapper.prototype,
    ReactCompositeComponent, 
    {
        _instantiateReactComponent: instantiateReactComponent,
    }
);
Dadurch wird eine andere Datei ReactCompositeComponent:

// 文件位置:src/renders/shared/stack/reconciler/ReactCompositeComponent.js

var ReactCompositeComponent = {
    construct: function (element) {
        this._currentElement = element;
        this._rootNodeID = 0;
        this._compositeType = null;
        this._instance = null;
        this._hostParent = null;
        this._hostContainerInfo = null;

        // See ReactUpdateQueue
        this._updateBatchNumber = null;
        this._pendingElement = null;
        this._pendingStateQueue = null;
        this._pendingReplaceState = false;
        this._pendingForceUpdate = false;

        this._renderedNodeType = null;
        this._renderedComponent = null;
        this._context = null;
        this._mountOrder = 0;
        this._topLevelWrapper = null;

        // See ReactUpdates and ReactUpdateQueue.
        this._pendingCallbacks = null;

        // ComponentWillUnmount shall only be called once
        this._calledComponentWillUnmount = false;

        if (__DEV__) {
            this._warnedAboutRefsInRender = false;
        }
    }
    
    ...
}
aufgerufen. Wir verwenden

, um die hier generierte Komponente der obersten Ebene darzustellen. ReactCompositeComponent[T]

Der gesamte Aufrufstapel sieht so aus:

ReactDOM.render
|=ReactMount.render(nextElement, container, callback)
|=ReactMount._renderSubtreeIntoContainer()
    |-ReactMount._renderNewRootComponent(
        nextWrappedElement, // scr:------------------> ReactElement[2]
        container,          // scr:------------------> document.getElementById('root')
        shouldReuseMarkup,  // scr: null from ReactDom.render()
        nextContext,        // scr: emptyObject from ReactDom.render()
    )
    |-instantiateReactComponent(
          node,             // scr:------------------> ReactElement[2]
          shouldHaveDebugID /* false */
        )
        |-ReactCompositeComponentWrapper(
            element         // scr:------------------> ReactElement[2]
        );
        |=ReactCompositeComponent.construct(element)
Die hierarchische Struktur zwischen den Komponenten sieht so aus:

Analyse des ersten Renderings von React (reines DOM-Element)

Nachdem die Komponente der obersten Ebene erstellt wurde, besteht der nächste Schritt darin, batchedMountComponentIntoNode (Methode _renderNewRootComponent von ReactMount) aufzurufen, um die Seite zu rendern.


Das obige ist der detaillierte Inhalt vonAnalyse des ersten Renderings von React (reines DOM-Element). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen