Foto de Joshua Sortino en Unsplash
Comprender el código fuente de Reacción I
Comprender el código fuente de reacción II
Comprender el código fuente de la reacción III
Comprender el código fuente de React IV (este)
Comprender el código fuente de React V
Comprender el código fuente de reacción VI
Comprender el código fuente de React VII
Comprender el código fuente de reacción VIII
Comprender el código fuente de reacción IX
Hemos completado el proceso de renderizado de un componente simple. Esta vez vamos a explorar más ramificaciones de este proceso discutiendo cómo se representa un componente de clase (uno típico que podríamos usar en el desarrollo cotidiano).
Archivos utilizados en este artículo: lo mismo que publicar uno y dos
Utilizo {} para hacer referencia a la publicación anterior que es relevante para los métodos (o procesos lógicos) que se discuten.
El componente llamado App
es similar a lo que di al principio del post uno , en el cual lo consideramos demasiado complejo para principiantes. Pero desde que nos nivelamos un poco, ya no se ve tan desalentador.
importar React, {Component} de 'reaccionar';
importar el logo de './logo.svg';
import './App.css';
la aplicación de clase extiende el componente {
constructor (accesorios) {
super (apoyos);
this.state = {
desc: 'inicio',
};
}
render () {
regreso (
<div className = "App">
<div className = "App-header">
<img src = "main.jpg" className = "App-logo" alt = "logo" />
<h1> "Welcom reacciona" </ h1>
</ div>
<p className = "App-intro">
{this.state.desc}
</ p>
</ div>
);
}
}
exportar la aplicación predeterminada;
App@App.js
Como se mencionó, el componente anterior se representa usando:
ReactDOM.render (
<App />,
document.getElementById ('root')
);
Ahora el código etiquetado:
importar React, {Component} de 'reaccionar';
importar el logo de './logo.svg';
import './App.css';
la aplicación de clase extiende el componente {
constructor (accesorios) {
super (apoyos);
this.state = {
desc: 'inicio',
};
}
render () {
devolver React.createElement (
'div',
{className: 'App'},
React.createElement (
'div',
{className: 'App-header'},
React.createElement (
'img',
{src: "main.jpg", className: 'App-logo', alt: 'logo'}
),
React.createElement (
'h1',
nulo,
'' Welcom reacciona ''
)
),
React.createElement (
'pag',
{className: 'App-intro'},
this.state.desc
)
);
}
}
exportar la aplicación predeterminada;
...
ReactDOM.render (React.createElement (App, null), document.getElementById ('root'));
Aquí consideramos que Component
una clase base común, ya que no se usarán otros métodos en esta publicación.
Esta vez podemos adelantar la lógica que se comparte con el componente simple.
Construya the top level wrapper `ReactCompositeComponent[T]`
La estructura de datos designada:
Este paso es casi el mismo que en la representación de componente simple, por lo que daré una breve descripción,
1) crea ReactElement[1]
usando ReactElement.createElement(type, config, children)
(Esta vez la App
se pasa al type
, y config
, los children
son null
);
2) crea ReactElement[2]
en _renderSubtreeIntoContainer()
;
3) crea el contenedor designado con instantiateReactComponent()
.
ReactElement.createElement(type, // scr: -------------> App
config, // scr: -------------> null
children // scr: -------------> null
) // scr: ------------------------------------------------------> 1)
ReactDOM.render
| = ReactMount.render (nextElement, contenedor, devolución de llamada)
| = ReactMount._renderSubtreeIntoContainer (
parentComponent, // scr: ----> null
nextElement, // scr: ----> ReactElement [1]
contenedor, // scr: ----> document.getElementById ('root')
callback '// scr: ----> undefined
) // scr:------------------------------------------------------> 2)
| -instantiateReactComponent (// scr: -------------------------> 3)
nodo, // scr: ------> ReactElement [2]
shouldHaveDebugID / * falso * /
)
| -ReactCompositeComponentWrapper (
elemento // scr: ------> ReactElement [2]
);
| = ReactCompositeComponent.construct (element / * same * /)
Esto es lo que cubrimos en { post one }.
Inicializa `ReactCompositeComponent [T]`
La estructura de datos designada:
El paso es el mismo también:
1) ReactDOMContainerInfo[ins]
representa el contenedor elemento DOM, document.getElementById('root')
;
2) TopLevelWrapper
se TopLevelWrapper
una instancia ( TopLevelWrapper[ins]
) y se establece en la ReactCompositeComponent[T]._instance
junto con la inicialización de otras propiedades;
3) De nuevo, mountComponentIntoNode
es el punto de cruce de la mitad superior e inferior, dentro del cual ReactCompositeComponent[T].mountComponent
devuelve un DOMLazyTree
completo que puede ser utilizado por ReactMount._mountImageIntoNode
, un método de la mitad inferior.
ReactDOM.render ___
| = ReactMount.render (nextElement, contenedor, devolución de llamada) |
| = ReactMount._renderSubtreeIntoContainer () |
| -ReactMount._renderNewRootComponent () |
| -instantiateReactComponent () |
| ~ batchedMountComponentIntoNode () mitad superior
| ~ mountComponentIntoNode () (plataforma independiente)
| -ReactReconciler.mountComponent () // scr -----> 1) |
| -ReactCompositeComponent [T] .mountComponent () scr:> 2) 3)
... _ | _
...
mitad inferior
| -_mountImageIntoNode () (HTML DOM específico)
Esto es lo que cubrimos en la primera parte de {post two }.
Excepto por algunas pequeñas diferencias en cuanto a los valores de los argumentos, las operaciones relacionadas con los niveles superiores de envoltura son exactamente las mismas que las que discutimos en las publicaciones anteriores para el componente simple. Después de completar esas operaciones, la lógica procesa la primera ramificación que es específica para el componente de la clase.
`ReactCompositeComponent [T] .performInitialMount ()` – crea un `ReactCompositeComponent` de` ReactElement [1] `
Este paso quita el contenedor y crea otra instancia de ReactCompositeComponent
para reflejar el componente de clase, la App
.
La estructura de datos designada:
La pila de llamadas en acción:
...
| ~ mountComponentIntoNode () |
| -ReactReconciler.mountComponent () |
| -ReactCompositeComponent [T] .mountComponent () |
/ * estamos aquí * / |
| -ReactCompositeComponent [T] .performInitialMount (|
renderedElement, // scr: -------> undefined |
hostParent, // scr: -------> null mitad superior
hostContainerInfo, // scr: -------> | ReactDOMContainerInfo[ins] |
transacción, // scr:------->
sin interés |
contexto, // scr:------->
sin interés |
) |
El proceso es muy similar al performInitialMount()
en { post two }. La única diferencia aquí es que, basado en ReactElement[1].type
_instantiateReactComponent
, _instantiateReactComponent
crea un ReactCompositeComponent
para el componente de clase ( App
) en lugar de un ReactDOMComponent
. Para decirlo brevemente:
1) llama a _renderValidatedComponent()
que a su vez llama a TopLevelWrapper.render()
para extraer ReactElement[1]
; 2) ReactCompositeComponent
una instancia de un ReactCompositeComponent
con _instantiateReactComponent
(llamamos al objeto ReactCompositeComponent[ins])
; y 3) llama a ReactCompositeComponent[ins].mountComponent
(recursivamente) a través de ReactReconciler
, y pasa al siguiente paso.
performInitialMount: function (
renderedElement,
hostParent,
hostContainerInfo,
transacción,
contexto)
{
var inst = this._instance;
...
if (inst.componentWillMount) {
... // scr: no definimos componentWillMount () en la aplicación
}
// Si no es un componente sin estado, ahora renderizamos
if (renderedElement === undefined) {
renderedElement = this._renderValidatedComponent (); // scr:> 1)
}
var nodeType = ReactNodeTypes.getType (renderedElement); // scr: -> el tipo es ReactNodeTypes.Composite esta vez
this._renderedNodeType = nodeType;
var child = this._instantiateReactComponent (renderedElement, nodeType! == ReactNodeTypes.EMPTY / * shouldHaveDebugID * /
); // scr: ---------------------------------------------- > 2)
this._renderedComponent = child;
var markup = ReactReconciler.mountComponent (child, transaction, hostParent, hostContainerInfo, this._processChildContext (context), debugID); // scr: ---------------------------------------------- > 3)
... // scr: código DEV
marcado de devolución;
},
ReactCompositeComponent@renderers/shared/stack/reconciler/ReactCompositeComponent.js
`ReactCompositeComponent [ins] .mountComponent ()` – initialize `ReactCompositeComponent [ins]`
La estructura de datos designada:
La pila de llamadas en acción:
...
| ~ mountComponentIntoNode () |
| -ReactReconciler.mountComponent () |
| -ReactCompositeComponent [T] .mountComponent () |
| -ReactCompositeComponent [T] .performInitialMount () mitad superior
| -ReactReconciler.mountComponent () |
/ * estamos aquí * / |
| -ReactCompositeComponent [ins] .mountComponent (same) |
Igual que en ReactCompositeComponent[T].mountComponent()
{post two }, la tarea más importante de este paso es crear una instancia de la App
con ReactCompositeComponent[ins]._currentElement
( ReactElement[1]
).
La línea en el método que hace el trabajo es:
...
var inst = this._constructComponent (
doConstruct,
publicProps,
publicContext,
updateQueue,
);
...
ReactCompositeComponent@renderers/shared/stack/reconciler/ReactCompositeComponent.js
en el que se llama al constructor de la App
.
...
constructor (accesorios) {
super (apoyos);
this.state = {
desc: 'inicio',
};
}
...
// copiado desde el comienzo de este texto
Entonces (lo ReactCompositeComponent[ins]._instance
), la App[ins]
está configurada en la ReactCompositeComponent[ins]._instance
y también se crea un back-link a través de ReactInstanceMap
.
Esta es la instancia de
App
componente personalizado que responde a suthis.setState(…)
.
Otras operaciones incluyen: 1) App[ins].props
reference ReactElement[1].props
; y 2) ReactCompositeComponent[ins]._mountOrder
se establece en 2
debido a que ++
opera en la variable global nextMountID
.
Es importante tener en cuenta que App[ins].render()
es otro método de App
que definimos al principio. A diferencia de TopLevelWrapper[ins].render()
que devuelve una instancia concreta de ReactElement
, App[ins].render()
basa en React.createElement()
en el momento en que se invoca. Vamos a visitar este método pronto.
Como este paso es muy similar al que inicializa ReactCompositeComponent[T]
{post two }, no examinamos más el método mountComponent()
es decir, mountComponent()
).
mountComponent: function (
transacción,
hostParent,
hostContainerInfo,
contexto,
// scr: this ------> ReactCompositeComponent [T]
) {
...
this._mountOrder = nextMountID ++; // scr: --------------------> 2)
...
var publicProps = this._currentElement.props; // scr: -----------> {child: ReactElement [1]}
...
// scr: ---------------------------------------------- ---> crítico)
var inst = this._constructComponent (
doConstruct,
publicProps,
publicContext,
updateQueue,
); // scr: ----------> llamar al constructor de TopLevelWrapper
var renderedElement;
...
// Deben configurarse en el constructor, pero como una conveniencia
// para abstracciones de clase más simples, los configuramos después del hecho.
// scr: ---------------------------------------------- ----------> 1)
inst.props = publicProps; // scr: ----> {child: ReactElement [1]}
...
// scr: ---------------------------------------------- -> crítico)
this._instance = inst; // scr: ---------------------------------> vincula ReactCompositeComponent [T] a la instancia de TopLevelWrapper
// Almacena una referencia de la instancia a la representación interna
ReactInstanceMap.set (inst, this); // scr: ----------------------> vincula la instancia de TopLevelWrapper a ReactCompositeComponent [T]
...
var markup;
if (inst.unstable_handleError) {// scr: -----------------------> falso, TopLevelWrapper.prototype.unstable_handleError no está definido
...
} else {
// scr: ---------------------------------------------- ---> siguiente)
markup = this.performInitialMount (// scr: una inicial al final?
renderedElement,
hostParent,
hostContainerInfo,
transacción,
contexto,
);
}
...
marcado de devolución;
}
ReactCompositeComponent@renderers/shared/stack/reconciler/ReactCompositeComponent.js
`ReactCompositeComponent [ins] .performInitialMount ()` – crea un `ReactDOMComponent`
...
| ~ mountComponentIntoNode () |
| -ReactReconciler.mountComponent () |
| -ReactCompositeComponent [T] .mountComponent () |
| -ReactCompositeComponent [T] .performInitialMount () mitad superior
| -ReactReconciler.mountComponent () |
/ * estamos aquí * / |
| -ReactCompositeComponent [ins] .mountComponent () |
| -this.performInitialMount () |
| -this._renderValidatedComponent () |
| -instantiateReactComponent () _ | _
| -ReactDOMComponent[6].
mountComponent()
mitad inferior
Estamos aquí de nuevo:
performInitialMount: function (
renderedElement,
hostParent,
hostContainerInfo,
transacción,
contexto)
{
var inst = this._instance;
...
if (inst.componentWillMount) {
... // scr: no definimos componentWillMount () en la aplicación
}
// Si no es un componente sin estado, ahora renderizamos
if (renderedElement === undefined) {
renderedElement = this._renderValidatedComponent (); // scr:> 1)
}
var nodeType = ReactNodeTypes.getType (renderedElement); // scr: -> el tipo es ReactNodeTypes.Host esta vez
this._renderedNodeType = nodeType;
var child = this._instantiateReactComponent (renderedElement, nodeType! == ReactNodeTypes.EMPTY / * shouldHaveDebugID * /
); // scr: ---------------------------------------------- > 2)
this._renderedComponent = child;
var markup = ReactReconciler.mountComponent (child, transaction, hostParent, hostContainerInfo, this._processChildContext (context), debugID); // scr: ---------------------------------------------- > 3)
... // scr: código DEV
marcado de devolución;
},
ReactCompositeComponent@renderers/shared/stack/reconciler/ReactCompositeComponent.js
Antes de que se ReactDOMComponent
un ReactDOMComponent
(sabemos que esta es la clase que maneja las operaciones DOM), se debe ReactElement
el ReactElement
dentro de la App[ins]
. Para hacerlo, se llama a la App[ins].render()
por la siguiente línea (en _renderValidatedComponent()
) {post two}
...
renderedElement = this._renderValidatedComponent ();
...
Luego, los desencadenantes de App[ins].render()
1) Las llamadas en cascada de React.createElement()
Para comprender cómo se establece el árbol ReactElement
, primero App.render()
implementación de App.render()
:
render () {
return React.createElement (// scr: -----------> 5)
'div',
{className: 'App'},
React.createElement (// scr: -----------> 3)
'div',
{className: 'App-header'},
React.createElement (// scr: -----------> 1)
'img',
{src: "main.jpg", className: 'App-logo', alt: 'logo'}
),
React.createElement (// scr: -----------> 2)
'h1',
nulo,
'' Welcom reacciona ''
)
),
React.createElement (// scr: -----------> 4)
'pag',
{className: 'App-intro'},
this.state.desc
)
);
}
// copiado desde el comienzo de este texto
En este fragmento de código también doy el orden de llamada de createElement()
s que sigue un principio muy simple: los argumentos deben resolverse (con createElement()
) de izquierda a derecha antes de createElement()
una función (de createElement()
).
Luego, podemos examinar la creación de cada ReactElement
{ post one }.
React.createElement (// scr: --------------------------------> 1)
'img',
{src: "main.jpg", className: 'App-logo', alt: 'logo'}
),
crea ReactElement[2]
:
; y
React.createElement (// scr: --------------------------------> 2)
'h1',
nulo,
'Bienvenido a React'
)
crea ReactElement[3]
:
(Ahora se resuelven los dos argumentos para 3).
; y
React.createElement (// scr: -----------> 3)
'div',
ReactElement[2]
,
ReactElement[3]
),
crea ReactElement[4]
:
; y
React.createElement (// scr: -----------> 4)
'pag',
{className: 'App-intro'},
this.state.desc
)
crea ReactElement[5]
:
(Ahora los argumentos para 5) están resueltos.)
; y
return React.createElement (// scr: -----------> 5)
'div',
{className: 'App'},
ReactElement[4]
,
ReactElement[5]
)
crea ReactElement[6]
:
.
Combinados juntos obtuvimos el árbol de elementos al que se hace referencia por renderedElement
:
2)`
ReactCompositeComponent [ins] ._ instantiateReactComponent ()` – Create `ReactDOMComponent[6]`
La estructura de datos designada:
El árbol de elementos creado en el último paso se usa para crear ReactDOMComponent[6]
en la siguiente línea (dentro de _instantiateReactComponent()
) { post two }
var child = this._instantiateReactComponent (
renderedElement,
nodeType! == ReactNodeTypes.EMPTY / * shouldHaveDebugID * /,
);
3) Ahora ReactReconciler.mountComponent()
llama al mountComponent()
del ReactDOMComponent[6]
y los procesos lógicos a la mitad inferior.
continuará…