Entiendo que React usa React.createElement() de forma recursiva para crear el DOM virtual.
Por ejemplo: si tenemos un componente de App que tiene este marcado:
<div className="app"> <span>3<span/> <Br /> content 1 <div/>Se convierte en:
ReactDOM.render(React.createElement(App, {}))y esto devuelve este objeto:
{ type: App, props: {}, } y esto llamará a otro React.createElement
React.createElement('div', { className: 'app"}, //children)y esto devolverá este objeto:
{ type: 'div', props: { className: 'app', children: [ React.createElement('span', {}, 3), React.createElement('br'), 'content 1' ] } }y este proceso continúa hasta que se crea todo el DOM virtual.
Ahora, cuando ReactDOM.render() funciona, utiliza estos objetos para crear los nodos DOM reales en el navegador.
Estoy leyendo este artículo que explica bien el proceso, pero algo me confunde aquí,
Si un atributo de tipo contiene una cadena con un nombre de etiqueta, cree una etiqueta con todos los atributos enumerados en props.
Si tenemos una función o una clase bajo tipo, llámela y repita el proceso recursivamente en un resultado.
Si hay elementos secundarios debajo de los accesorios, repita el proceso para cada elemento secundario uno por uno y coloque los resultados dentro del nodo DOM del elemento principal.
Mi problema está aquí:
Si tenemos una función o una clase bajo tipo, llámela y repita el proceso recursivamente en un resultado
¿Por qué ReactDOM.render() simplemente no usa los objetos creados por React.createElement() en lugar de volver a llamar a los componentes de la función para obtener los elementos DOM subyacentes? ¿Me estoy perdiendo de algo? Si React.createElement() devuelve todos los detalles sobre el componente, ¿por qué necesitamos hacerlo de nuevo?
Creo que parte del problema es que la información en la premisa que proporcionó está demasiado simplificada en comparación con el valor de retorno real de React.createElement . Veamos un ejemplo real con un componente principal que usa una instancia del enlace de estado y un componente secundario que usa sus accesorios (sin ningún JSX, como en su publicación):
<div id="root"></div> <script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script> <script type="module"> const {createElement, useState} = React; function Count (props) { return createElement('span', null, props.value); } function App () { const [count, setCount] = useState(0); const reactElement = createElement( 'div', null, createElement( 'div', null, createElement('span', null, 'Count:'), ' ', createElement(Count, {value: count}), ), createElement('button', {onClick: () => setCount(n => n + 1)}, 'Increment'), ); console.log(reactElement); return reactElement; } ReactDOM.render(createElement(App), document.getElementById('root')); </script> Mire la consola JS en su navegador cuando ejecute el ejemplo anterior y examine el objeto props en el elemento de reacción registrado. Ubique la propiedad children en props y examine cada objeto en la matriz. Luego repita este proceso para cada objeto en la matriz de forma recursiva, hasta el final de la jerarquía de nodos.
Después de estudiar los valores, haga clic en el botón "Incrementar" en el ejemplo y vuelva a examinar la estructura (recursivamente) después de volver a renderizar. Encontrará diferencias en la estructura, y algunas de estas diferencias son causadas por los cambios en el objeto props que se pasan al componente de función Count . Este ejemplo simple ilustra una de las razones por las que es necesario invocar cada componente funcional en cada renderizado; sin embargo, hay muchos más valores de estado internos creados y utilizados por React que dependen de la invocación determinista de estas funciones en cada renderizado.