Maison >interface Web >js tutoriel >Analyse du premier rendu de React (élément DOM pur)
Le contenu de cet article concerne l'analyse du premier rendu de React (éléments DOM purs). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
React est une très grande bibliothèque. Puisque ReactDom et ReactNative doivent être pris en compte en même temps, ainsi que le rendu du serveur, etc., le code a un haut degré d'abstraction et un niveau de lecture très profond. son code source est un processus très difficile. Dans le processus d'apprentissage du code source de React, cette série d'articles m'a le plus aidé, j'ai donc décidé de parler de ma compréhension sur la base de cette série d'articles. Cet article utilisera de nombreux exemples du texte original. Si vous souhaitez ressentir le sentiment original, il est recommandé de lire le texte original.
Cette série d'articles sera basée sur React 15.4.2.
Lors de l'écriture de projets React, nous les écrivons généralement directement sous la forme de JSX, et JSX est compilé par Babel Enfin , la balise HTML sera convertie en forme de fonction de React.createElement. Si vous souhaitez approfondir votre compréhension, vous pouvez lire cet article que j'ai écrit auparavant : Virtual DOM vous ne connaissez pas (1) : Introduction à Virtual Dom. La fonction h dans l'article est par défaut React.createElement si elle n'est pas configurée dans Babel.
Ci-dessous, nous prendrons un exemple simple pour voir comment React rend
ReactDOM.render( <h1>hello world</h1>, document.getElementById('root') );
Après la compilation JSX, cela ressemblera à ceci
ReactDOM.render( React.createElement( 'h1', { style: { "color": "blue" } }, 'hello world' ), document.getElementById('root') );
Jetons un coup d'oeil au code source de React.createElement
en premier.
// 文件位置:src/isomorphic/React.js var ReactElement = require('ReactElement'); ... var createElement = ReactElement.createElement; ... var React = { ... createElement: createElement, ... } module.exports = React;
L'implémentation finale doit être visualisée 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> ne fait essentiellement que 3 choses : </p><ol class=" list-paddingleft-2"> <li><p> filtrera Après cela, copiez les attributs valides de config vers props</p></li> <li><p>Copier les enfants dans l'attribut props.children sous la forme d'un tableau</p></li> <li><p>Attribution d'attribut par défaut </p></li> </ol><p> 🎜><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; };La valeur de retour finale est
. Jetons un coup d'œil à ce qu'il fait
React.createElement |=ReactElement.createElement(type, config, children) |-ReactElement(type,..., props)
En fin de compte, il renvoie simplement un objet simple. La pile d'appels ressemble à ceci : ReactElement[1]
// 文件位置: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; },
ReactDom.render finira par appeler _renderSubtreeIntoContainer de ReactMount :
// 文件位置: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, } );
Ici encore, appeler un autre fichier instantiateReactComponent :
// 文件位置: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; } } ... }
Cela appellera un autre fichier ReactCompositeComponent : ReactCompositeComponent[T]
Nous utilisons
pour représenter le composant de niveau supérieur généré ici.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)
L'ensemble de la pile d'appels est comme ceci :
La structure hiérarchique entre les composants est comme ceci :
Une fois le composant de niveau supérieur construit, l'étape suivante consiste à appeler batchedMountComponentIntoNode (méthode _renderNewRootComponent de ReactMount) pour afficher la page.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!