Inicio / Artículos

Desmitificando la comparación del DOM virtual: qué compara React y por qué es útil

Comprenda qué es realmente el DOM virtual de React, cómo reconcilia las diferencias entre dos árboles de elementos, qué cambios ocurren en la fase de confirmación y de dónde proviene el beneficio en rendimiento.

Editor: REACTAPP.TOP4 min de lectura1032 palabras

Fuentes: How React Virtual DOM Works Under the Hood

Las interfaces cambian constantemente: aparece una notificación, un botón se activa o desactiva, un contador avanza y una lista se vuelve a renderizar. Cada uno de estos cambios debe llegar al DOM del navegador, y actualizar el DOM de forma descuidada es una forma segura de hacer que una página parezca lenta. La solución de React es el DOM virtual junto con un paso de comparación llamado reconciliación. Este artículo explica qué mantiene React en memoria, cómo decide qué ha cambiado y por qué eso ayuda, para que pueda razonar sobre las actualizaciones con un modelo mental preciso.

Por qué escribir directamente en el DOM resulta costoso

Antes de React, las actualizaciones de la interfaz eran imperativas: encontrar un nodo y modificarlo.

document.getElementById("title").innerText = "Hello";

Eso está bien en una página pequeña. Cuando cientos o miles de elementos cambian con frecuencia, se vuelve lento y difícil de gestionar, ya que un cambio en el DOM puede obligar al navegador a volver a realizar:

  • el cálculo de estilos y diseño
  • la reorganización del contenido circundante
  • Recoloración de los píxeles afectados
  • Volver a renderizar partes de la página
  • Cada vez, el navegador vuelve a calcular dónde se encuentran los elementos, cuán grandes son y qué píxeles deben volverse a dibujar. Ese proceso es mucho más costoso que crear o comparar objetos JavaScript. Además de este costo, muchos fragmentos de código que acceden al DOM de forma independiente hacen que la pantalla se desincronice fácilmente con el estado de la aplicación.

    Qué es realmente el DOM virtual

    El DOM real

    El DOM real es el árbol de nodos en tiempo real que el navegador construye a partir del marcado, con un nodo por elemento. Incluso esto:

    <body>
      <h1>Hello</h1>
    </body>
    

    se convierte en un árbol interno vinculado al diseño y al dibujo, y mutarlo con frecuencia es lo que desencadena el costoso proceso mencionado anteriormente.

    La representación virtual

    El DOM virtual se denomina a menudo una copia ligera del DOM real. Más precisamente, es una descripción de cómo debería verse la interfaz de usuario: objetos simples que devuelven los componentes al renderizarse. React actualiza primero esta descripción y luego interviene en el navegador. Un elemento se ve más o menos así:

    {
      type: "h1",
      props: {
        children: "Hello"
      }
    }
    

    Estos objetos son económicos de crear y comparar, por lo que React puede determinar qué ha cambiado antes de realizar cualquier operación real en el DOM. JSX es simplemente la sintaxis para generarlos.

    Desde el primer render hasta un árbol modificado

    En el primer render de un componente como este:

    function App() {
      return <h1>Hello World</h1>;
    }
    

    React construye el árbol virtual, crea nodos DOM correspondientes e los inserta en la página. Ahora ambos árboles coinciden y la interfaz de usuario se vuelve visible.

    Más tarde, un manejador de clic podría actualizar el estado:

    setCount(count + 1);
    

    o cuando un padre pasa nuevos propios. Eso indica que alguna parte de la interfaz de usuario podría necesitar cambios. React no modifica inmediatamente el DOM; programa un nuevo renderizado, y las actualizaciones provenientes del mismo evento suelen agruparse juntas.

    Durante ese renderizado, React llama nuevamente al componente y obtiene un árbol actualizado, de modo que ahora contiene tanto la versión anterior como la nueva. El árbol antiguo:

    <h1>Hello</h1>
    

    El árbol nuevo:

    <h1>Hello Omer</h1>
    

    La tarea consiste en determinar con exactitud qué es lo que difiere.

    Reconciliación: cómo funciona la comparación

    La reconciliación significa comparar el árbol virtual anterior con el nuevo; esta comparación en sí suele denominarse diferenciación. Para cada posición, React verifica si un elemento ha cambiado, permanecido igual o ha sido añadido o eliminado. Conceptualmente:

    Old Tree  VS  New Tree
    

    El objetivo es realizar el conjunto más pequeño posible de cambios para transformar la interfaz antigua en la nueva. Una comparación completa de árboles sería demasiado lenta, por lo que React utiliza dos heurísticas. Si el tipo de un elemento cambia, por ejemplo de div a span, React reemplaza ese subárbol en lugar de comparar sus hijos. En listas, compara los hijos por medio de la key, y por eso son importantes las claves estables: indican a React que un elemento se ha movido en lugar de haber sido reemplazado.

    Cuando solo cambia el texto

    Antes:

    <h1>Hello</h1>
    

    Después:

    <h1>Hello Omer</h1>
    

    El <h1> mantiene el mismo tipo en la misma posición; solo su texto difiere. Por lo tanto, React conserva el nodo DOM existente y actualiza únicamente el nodo de texto en lugar de recrear el elemento. Evitar todas las operaciones que no sean estrictamente necesarias es la base de esta optimización.

    La fase de commit: aplicar solo lo que cambió

    Después de realizar la comparación, React escribe los cambios resultantes en el DOM real:

    • actualizar texto
    • establecer o eliminar atributos
    • insertar nuevos elementos
    • eliminar elementos que desaparecieron

    Esta es la fase de commit, el único momento en que React interactúa con el DOM, y solo modifica lo que indicó la comparación. Luego, el navegador vuelve a dibujar las áreas afectadas. Para conocer con más detalle cómo se pasa de un commit a píxeles en la pantalla, consulte nuestra guía sobre el renderizado de React desde actualizaciones de estado hasta píxeles en la pantalla.

    De dónde proviene la mejora de rendimiento

    La ventaja proviene de menos operaciones costosas en el DOM. En lugar de reconstruir todo, React compara las descripciones antiguas y nuevas, calcula las diferencias mínimas y solo modifica los nodos afectados. Dado que la comparación de objetos es mucho más económica que la mutación del DOM, esto suele ser beneficioso en aplicaciones grandes.

    Dos consideraciones mantienen la fiabilidad del modelo. El DOM virtual no es inherentemente más rápido que un código DOM cuidadosamente optimizado; su valor radica en permitirte escribir interfaces de usuario declarativas mientras se logran actualizaciones eficientes. Además, el renderizado no es gratuito: React sigue llamando a tus componentes y comparando sus resultados, por lo que evitar los re-renderizos innecesarios sigue siendo importante.

    Puntos clave

    • El DOM virtual es un conjunto de objetos simples que describen la interfaz de usuario deseada, y se recrea en cada renderizado.
  • Reconcilia las diferencias entre los árboles antiguos y nuevos utilizando el tipo de elemento y la key como atajos.
  • La fase de commit es el único lugar donde React escribe en el DOM, y solo guarda las diferencias.
  • Intercambias algo de trabajo de renderizado y comparación por muchas menos mutaciones costosas en el DOM y un modelo de programación más simple.
  • Lecturas relacionadas