Cómo funciona React bajo el capó

React es una biblioteca de JavaScript muy popular. Con más de 5,5 millones de descargas semanales, React disfruta de una gran popularidad. Pero no muchos desarrolladores de React saben cómo funciona React bajo el capó.

En esta publicación, intentaré descubrir algunas cosas interesantes sobre React que a usted, como desarrollador de React, le pueden resultar fascinantes. Empecemos desde el principio.

Pero antes de comenzar, si eres un desarrollador de React, ¡tengo noticias emocionantes para ti! Una vez que complete este artículo, podrá desarrollar algo genial con React y ganar premios en el camino :)

¿Qué hace React?

En esencia, React básicamente mantiene un árbol para ti. Este árbol es capaz de realizar cálculos de diferencias eficientes en los nodos.

Piense en su código HTML como un árbol. De hecho, así es exactamente como el navegador trata su DOM (su HTML renderizado en el navegador). React le permite reconstruir efectivamente su DOM en JavaScript y enviar solo aquellos cambios en el DOM que realmente ocurrieron.

JSX es azúcar sintáctico

No hay nada como JSX, ni para JavaScript ni para el navegador. JSX es simplemente azúcar sintáctico para crear objetos JavaScript muy específicos.

Cuando escribes algo como:

const tag = 

Hello

lo que estás haciendo esencialmente es esto:

const tag = React.createElement("h1", {}, "Hello")

Verá, cuando comienza a escribir cosas anidadas, no solo es difícil de codificar, sino que también se vuelve muy inconveniente mantener tal base de código. Por tanto, JSX le ayuda a llevar la limpieza de HTML al poder de JavaScript.

Pero, ¿qué hace React.createElement por sí mismo? Crea un objeto JavaScript simple y antiguo. De hecho, puede llamarlo manualmente y verlo usted mismo.

Verá, tenemos un objeto como este:

{ $$typeof: Symbol(react.element), key: null, props: {children: "Hello"}, ref: null, type: "div" }

Y si comenzamos a anidar elementos como este:

React.createElement('div', { }, React.createElement('p', {}, 'A p inside a div') ) 

Comenzaríamos a obtener objetos anidados:

Entonces, ya lo sabe, una vez que se analiza todo el JSX y se han resuelto todas las llamadas a React.createElement, aterrizamos con un objeto anidado gigante como el anterior.

React Renderer

Ahora, si regresa al punto donde iniciamos nuestra aplicación, verá que en su archivo index.js, encontrará la siguiente línea:

// .. prev code ReactDOM.render(, container)

Desde arriba, sabemos que cuando se ha terminado de analizar, esto es solo un gran objeto de los elementos de React. Entonces, ¿cómo puede React construir divs reales y etiquetas p a partir de él? Conoce ReactDOM.

ReactDOM, a su vez, crea nodos de forma recursiva en función de su propiedad de 'tipo' y los añade finalmente al DOM.

¡Debería quedar claro en este punto que por qué desvincular React de los renderizadores es en realidad un gran movimiento! Lo que hace React es simplemente construir un árbol de UI que podría usarse no solo en la web, sino también en entornos como el móvil, dado que hay un renderizador disponible que puede comunicarse con el sistema operativo host. Aquí entra en juego React Native. Verá, React Native usa la biblioteca React, pero no ReactDOM como render. En cambio, el paquete react-native es en sí mismo un renderizador.

Hacemos esto en una aplicación nativa de reacción para iniciar la aplicación:

const { AppRegistry } = require('react-native') AppRegistry.registerComponent('app', () => MainComponent)

¡Mira! Sin ReactDOM. Por qué no? Debido a que no tenemos métodos como appendChild, tampoco tenemos un entorno tipo DOM. En cambio, para los móviles, necesitamos soporte para la interfaz de usuario directamente desde el sistema operativo. Pero la biblioteca React no necesita saber eso, el renderizador (React Native) se encarga de eso.

Reaccionar reconciliación

Cuando decimos que React mantiene una copia de DOM usando DOM virtual en JavaScript, y lo usa para diferenciarlo a cualquier cambio y aplicarlo al DOM real, no queremos que React utilice la fuerza bruta a su manera. Reaccionar, de hecho hace una reconciliación muy perezosa. React haría la menor cantidad posible de cambios, es decir, intentaría reutilizar elementos, atributos e incluso estilos si es posible.

Considere este ejemplo:

stuff

Digamos que cambia esta expresión JSX a la siguiente usando alguna condición o algún estado:

something else

Ahora, mientras difiere, React lo vería bien, la etiqueta img hace uso del mismo className tanto en árboles antiguos como en nuevos, así que ¿por qué modificarlo? Y simplemente modificaría su atributo alt y seguiría adelante.

Sin embargo, hay una trampa. Debido a que no queremos que React haga muchos cálculos en la parte diferente, React asumiría que si un padre ha cambiado, el subárbol que lo contiene definitivamente ha cambiado. Por ejemplo:

I did not change

Si cambia este JSX al siguiente usando condición / estado:

I did not change

Aunque puede ver que no necesitamos volver a crear la etiqueta p interna, pero React no tiene forma de saberlo mientras atraviesa el árbol desde la parte superior (a menos que, por supuesto, realice una diferenciación de árbol pesada, que son algoritmos mucho más costosos la reacción heurística O (n) sigue para diferir). Entonces, React decide destruir a todos los niños (es decir, llamar a sus funciones de limpieza en useEffect, o componentWillUnmount en componentes basados ​​en clases) y volver a crear los niños desde cero.

Reaccionar claves

Al agregar / eliminar elementos en un nodo, React simplemente recorrería los elementos secundarios en el árbol antiguo y los elementos secundarios en el nuevo árbol del nodo y marcaría los lugares donde necesita realizar cualquier adición / eliminación. Pero esto tiene una desventaja sin la ayuda adicional del desarrollador. Considere este ejemplo:

  • A
  • B

Considere que esto se cambia a lo siguiente por condición / estado:

  • Z
  • A
  • B

Ahora, cuando React comenzara a comparar las dos listas para determinar la diferencia, encontraría la diferencia en el nodo hijo 1, mutaría la antigua A a la nueva Z, luego nuevamente en el nodo hijo 2, la mutaría de la antigua B a la nueva A, y luego, finalmente, agregue el nuevo nodo B.

Sin embargo, una mejor manera habría sido preservar los nodos A y B existentes y simplemente anteponer el nodo Z. Pero, ¿cómo iba a saber React sobre eso? React keys ayudaría.

Las claves solo proporcionan una buena forma de Reaccionar para saber qué elementos han cambiado o no mientras difieren. Ahora, en lugar de comparar todo el elemento, React compararía las claves de los niños para ver qué elemento debe agregarse / eliminarse. La siguiente forma es una forma eficiente de realizar lo mismo:

  • A
  • B

Ahora, si esto se cambia a:

  • Z
  • A
  • B

React ahora sabría que las claves 'A' y 'B' ya existen, por lo que solo necesitamos agregar el nuevo elemento con la clave 'Z'.

¿Eres desarrollador de React? ¡Demuestra tus habilidades de React desarrollando un juego interactivo de 3 minutos en React y gana sudaderas con capucha, camisetas y tazas de café ! Participe en codecomp uniéndose al servidor discord de codedamn aquí

Entonces, estos fueron algunos conceptos importantes que creo que serían realmente útiles para ustedes, como desarrolladores de React, para comenzar a comprender el núcleo de React y cómo funciona realmente. No dude en enviarnos cualquier sugerencia o pregunta que tenga sobre el mismo.

Puedes seguirme en Twitter para obtener más tweets de JS / codificación y otras cosas. ¡Paz!