In Desarrollo Última actualizaciónated:
Comparte en:
Software de Jira es la herramienta de gestión de proyectos número uno utilizada por equipos ágiles para planificar, rastrear, lanzar y respaldar software excelente.

Junto con la vida, la muerte, fatee impuestos, el comportamiento de renderizado de React es uno de los mejoresateprimeras verdades y misterios de la vida.

¡Vamos a bucear!

Como todos los demás, comencé mi viaje de desarrollo de front-end con jQuery. La manipulación de DOM basada en JS pura era una pesadilla en ese entonces, por lo que era lo que todos estaban haciendo. Luego, lentamente, Frameworks basados ​​en JavaScript se volvió tan prominente que ya no podía ignorarlos.

El primero que aprendí fue Vista. Lo pasé increíblemente difícil porque los componentes y st.ate y todo lo demás fue un tontoally nuevo modelo mental, y fue muy doloroso encajar todo. Pero eventualmenteally, lo hice, y acaricié miself en la espalda. Felicitaciones amigo, le dije a miself, has hecho la empinada subida; Ahora, el resto de los marcos, si alguna vez necesitas aprenderlos, será muy fácil.

Entonces, un día, cuando comencé aprendizaje Reaccionar, Me di cuenta de lo terriblemente equivocado que estaba. Facebook no facilitó las cosas al incluir Hooks y decirles a todos: “Oigan, usen esto de ahora en adelante. Pero no reescribas las clases; las clases estan bien. Actúally, no tanto, pero está bien. Pero los Hooks lo son todo y son el futuro.

¿Entendido? ¡Excelente!".

Eventoally, Yo también crucé esa montaña. Pero luego me golpeó algo tan importante y difícil como reaccionar.self: representación.

Si te has encontrado con el renderizado y sus misterios en React, sabes de lo que estoy hablando. Y si no lo ha hecho, ¡no tiene idea de lo que le espera! 😂

Pero antes de perder el tiempo en nada, es un buen ja.bit para preguntar qué ganarías con ello (a diferencia de mí, que soy un idiota sobreexcitado y felizmente aprenderé cualquier cosa porque sí 😭😭). Si su vida como desarrollador de React va bien sin preocuparse por cuál es esta representación, ¿por qué preocuparse? Buena pregunta, así que respondamos esto primero y luego veremos cómo funciona el renderizado.ally .

Why is understanding rendering behavior in React important?

Todos comenzamos a aprender React escribiendo componentes (hoy en día, funcionales) que devuelven algo llamado JSX. También entendemos que este JSX se convierte de alguna manera en elementos HTML DOM reales que aparecen en la página. las paginas actualizadasate como el state updates, las rutas cambian como se esperaba y todo está bien. Pero esta visión de cómo funciona React es ingenua y genera muchos problemas.

Si bien a menudo logramos escribir aplicaciones completas basadas en React, hay ocasiones en las que encontramos ciertas partes de nuestra aplicación (o la aplicación completa) notablemente lentas. Y la peor parte. . . ¡No tenemos ni idea de por qué! Hemos hecho todo correctamente, no vemos errores ni advertencias, hemos seguido todas las buenas prácticas de diseño de componentes, estándares de codificación, etc., y no hay lentitud en la red ni costosos cálculos de lógica empresarial entre bastidores. 🤔

A veces, es un niñoally Problema diferente: no hay nada malo con el rendimiento, pero la aplicación se comporta de manera extraña. Por ejemplo, realizar tres llamadas API al backend de autenticación pero solo una a todos los demás. O algunas páginas se vuelven a dibujar dos veces, y la transición visible entre las dos representaciones de la misma página crea una experiencia de usuario discordante.

Lo peor de todo es que no hay ayuda externa disponible en casos como estos. Si vas a tu foro de desarrollo favorito y haces esta pregunta, te responderán: “No puedo saberlo sin mirar tu aplicación. ¿Puede adjuntar un ejemplo de trabajo mínimo aquí? " Bueno, por supuesto, no puede adjuntar la aplicación completa por razones legales, mientras que un pequeño ejemplo funcional de esa parte puede no contener ese problema porque no interactúa con todo el sistema de la forma en que lo está en la aplicación real.

¿Atornillado? Sí, si me preguntas. 🤭🤭

So, unless you want to see such days of woe, I suggest you develop an understanding — and interest, I must insist; understanding gained reluctantly won’t get you far in the React world — in this poorly understood thing called rendering in React. Trust me, it’s not that hard to understand, and though it’s very difficult to master, you’ll go really lejos sin tener que conocer cada rincón.

¿Qué significa renderizar en React?

Esa, mi amigo, es una excelente pregunta. No tendemos a preguntarlo cuando aprendemos React (lo sé porque no lo hice) porque la palabra "renderizar" quizás nos adormece con una falsa sensación de familiaridad. Si bien el significado del diccionario es completamente diferente (y no es importante en esta discusión), los programadores ya tenemos una notion de lo que debe significar. Trabajar con pantallas, API 3D, tarjetas gráficas y leer especificaciones de productos entrena nuestra mente para pensar en algo como "pintar una imagen" cuando leemos la palabra "renderizar". En la programación de motores de juegos, hay un renderizador, cuyo único trabajo es, ¡precisamente!, pintar el mundo tal como lo entrega la escena.

Por eso pensamos que cuando React "renderiza" algo, recopila todos los componentes y vuelve a pintar el DOM de la página web. Pero en el mundo de React (y sí, incluso en la documentación oficial), el renderizado no se trata de eso. Entonces, apretémonos los cinturones de seguridad y profundicemos realmente en React. internals.

Debes haber oído que React mantiene lo que se llama un DOM virtual y que periódicamenteally lo compara con el DOM real y aplica los cambios necesarios (es por eso que no puedes simplemente agregar jQuery y React juntos; React necesita tomar el control total del DOM). Ahora bien, este DOM virtual no está compuesto por elementos HTML como el DOM real, sino por elementos de React. ¿Cual es la diferencia? ¡Buena pregunta! ¿Por qué no crear?ate ¿Una pequeña aplicación React y verlo por nosotros mismos?

yo creoated así aplicación React muy simple para este propósito. El código completo es solo un archivo que contiene algunas líneas:

import React from "react";
import "./styles.css";

export default function App() {
  const element = (
    <div className="App">
      <h1>Hello, there!</h1>
      <h2>Let's take a look inside React elements</h2>
    </div>
  );

  console.log(element);
  return element;
}

¿Se da cuenta de lo que estamos haciendo aquí?

Sí, simplemente registrando el aspecto de un elemento JSX. Estas expresiones y componentes JSX son algo que hemos escrito cientos de veces, pero rara vez prestamos atención a lo que sucede. Si abres tu browsConsola de desarrollo de er y ejecuta esta aplicación, verás un Object que se expande a:

Esto puede parecer intimidante, pero tome nota de algunos detalles interesantes:

  • Lo que estamos viendo es un objeto JavaScript normal y simple y no un nodo DOM.
  • Observe que la propiedad props dice que tiene un className of App (que es la clase CSS establecida en el código) y que este elemento tiene dos elementos secundarios (esto también coincide, los elementos secundarios son los <h1> y <h2> etiquetas).
  • La _source La propiedad nos dice dónde comienza el código fuente el cuerpo del elemento. Como puede ver, nombra el archivo App.js como fuente y menciona la línea número 6. Si vuelve a mirar el código, encontrará que la línea 6 está justo después de la etiqueta JSX de apertura, lo cual tiene sentido. Los paréntesis JSX que no contengo el elemento React; no son parte de ella, ya que sirven para transformarse en un React.createElement() llamar al later.
  • La __proto__ La propiedad nos dice que este objeto deriva todos sus. propiedades del JavaScript raíz Object, lo que refuerza nuevamente la idea de que solo estamos viendo objetos de JavaScript cotidianos aquí.

Entonces, ahora, entendemos que el llamado DOM virtual no se parece en nada al DOM real, sino que es un árbol de objetos React (JavaScript) que representan la interfaz de usuario en ese momento.

¿Agotado?

Créeme, yo también. 🙂 Dar vueltas a estas ideas una y otra vez en mi cabeza para tratar de presentarlas de la mejor manera posible, y luego pensar en las palabras para sacarlas a relucir y reorganizarlas, no es fácil. 😫

¡Pero nos estamos distrayendo!

Habiendo sobrevivido hasta aquí, ahora estamos en condiciones de responder la pregunta que buscábamos: ¿qué es el renderizado en React?

Bueno, el renderizado es el motor React. process caminando por el DOM virtual y recopilando el st actualate, accesorios, estructura, cambios deseados en la interfaz de usuario, etc. Reaccionar ahora actualizadoateMuestra el DOM virtual usando algunos cálculos y también compara el nuevo resultado con el DOM real en la página. Este cálculo y comparación es lo que hace el equipo de React.ally llama "reconciliación", y si está interesado en sus ideas y algoritmos relevantes, puede consultar el sitio oficial documentos.

¡Es hora de comprometerse!

Una vez finalizada la parte de renderizado, React inicia una fase llamada "commit", durante la cual aplica los cambios necesarios al DOM. Estos cambios se aplican synccronológicamente (uno tras otro, a través de un nuevo modo que funciona concurSe espera alquilar pronto), y el DOM está actualizado.ated. Exactamente cuándo y cómo React aplica estos cambios no es de nuestra incumbencia, ya que es algo que no está claro.ally bajo el capó y es probable que siga cambiando a medida que el equipo de React pruebe cosas nuevas.

Renderizado y rendimiento en aplicaciones React

A estas alturas ya hemos entendido que renderizar significa recopilar información y no es necesario que genere cambios visuales en el DOM cada vez. También sabemos que lo que consideramos “renderizado” es un proceso de dos pasos. process que implica renderizado y compromiso. Ahora veremos cómo se activa el renderizado (y más importante, el re-renderizado) en las aplicaciones React y cómo no conocer los detalles puede hacer que las aplicaciones funcionen mal.

Volver a renderizar debido a un cambio en el componente principal

Si un componente principal en React cambia (digamos, porque su state o se cambiaron los accesorios), React recorre todo el árbol hasta este elemento principal y vuelve a renderizar todos los componentes. Si su aplicación tiene muchos componentes anidados y muchas interacciones, sin saberlo, está sufriendo un gran impacto en el rendimiento cada vez que cambia el componente principal (asumiendo que es solo el componente principal que desea cambiar).

Es cierto que el renderizado no hará que React cambie el DOM real porque, durante la reconciliación, detectará que nada ha cambiado para estos componentes. Pero todavía se desperdicia tiempo de CPU y memoria, y te sorprendería.rised qué tan rápido se suma.

Reproducción debido a un cambio de contexto

La función Contexto de React parece ser la opción favorita de todos.ate-herramienta de gestión (algo para lo que no fue creado en absoluto). Es todo muy conveniente: simplemente incluya el componente superior en el proveedor de contexto y el resto es una cuestión sencilla. La mayoría de las aplicaciones de React se crean de esta manera, pero si has leído este artículo hasta ahora, probablemente hayas detectado el problema. Sí, cada vez que se actualiza el objeto de contexto.ated, desencadena una renderización masiva de todos los componentes del árbol.

La mayoría de las aplicaciones no tienen conciencia de rendimiento, por lo que nadie se da cuenta, pero como se dijo antes, tales descuidos pueden ser muy costosos en aplicaciones de alto volumen y alta interacción.

Mejorando el rendimiento de renderizado de React

Entonces, dado todo esto, ¿qué podemos hacer para mejorar el rendimiento de nuestras aplicaciones? Resulta que hay algunas cosas que podemos hacer, pero tenga en cuenta que solo discutiremos en el contexto de los componentes funcionales. Los componentes basados ​​en clases están muy desaconsejados por el equipo de React y están a punto de desaparecer.

Utilice Redux o bibliotecas similares para state-administración

Aquellos que aman el mundo rápido y sucio de Context tienden a hate Redux, pero esta cosa es muy popular por buenas razones. Y una de estas razones es el rendimiento: el connect() function in Redux is magical as it (almost always) correctly renders only those components as necessary. Yes, just follow the standard Redux architecture, and performance comes free. It’s not an exaggeration at all that if you adopt the Redux architecture, you avoid most of the performance (and other) problems right away.

Uso memo() para "congelar" componentes

El nombre "memo" proviene de Memoization, que es un nombre elegante para el almacenamiento en caché. Y si no ha encontrado mucho almacenamiento en caché, está bien; aquí estáateabajo roja description: cada vez que necesitas algún resultado de cálculo/operación, miras en el lugar donde has estado manteniendo prevbuenos resultados; si lo encuentras, genial, simplemente devuelve ese resultado; si no, continúe y realice esa operación/cálculo.

Antes de sumergirse directamente en memo(), primero veamos cómo ocurre la renderización innecesaria en React. Comenzamos con un escenario sencillo: una pequeña parte de la interfaz de usuario de la aplicación que muestra al usuario cuántas veces le ha gustado el servicio / producto (si tiene problemas para aceptar el caso de uso, piense en cómo en Medium puede "aplaudir ”Varias veces para mostrar cuánto apoyas / me gusta un artículo).

También hay un botón que les permite aumentar los Me gusta en 1. Y finally, there’s another component inside that shows the users their basic account details. Don’t worry at all if you’re finding this hard to follow; I’ll now provide step-by-step code for everything (and there isn’t much of it), and at the end, a link to a playground where you can mess with the working app and improve your understanding.

Primero abordemos el componente sobre información del cliente. vamos a crearate un archivo llamado CustomerInfo.js que contiene el siguiente código:

import React from "react";

export const CustomerInfo = () => {
  console.log("CustomerInfo was rendered! :O");
  return (
    <React.Fragment>
      <p>Name: Sam Punia</p>
      <p>Email: sampunia@gmail.com</p>
      <p>Preferred method: Online</p>
    </React.Fragment>
  );
};

Nada lujoso, ¿verdad?

Solo un texto informativo (que podría haber pasado a través de accesorios) que no se espera que cambie a medida que el usuario interactúa con la aplicación (para los puristas, sí, seguro que puede cambiar, pero el punto es que, en comparación con el resto). de la aplicación, es prácticaally estático). Pero note el console.log() statemento. Esta será nuestra pista para saber que el componente fue renderizado (recuerde, "renderizado" significa que su información fue recopilada y calculada).ated/compared, y no que fue pintado en el DOM real).

Entonces, durante nuestras pruebas, si no vemos tal mensaje en el browsEn la consola, nuestro componente no se renderizó en absoluto; si lo vemos aparecer 10 veces, significa que el componente fue renderizado 10 veces; etcétera.

Y ahora veamos cómo nuestro componente principal usa este componente de información del cliente:

import React, { useState } from "react";
import "./styles.css";
import { CustomerInfo } from "./CustomerInfo";

export default function App() {
  const [totalLikes, setTotalLikes] = useState(0);
  return (
    <div className="App">
      <div className="LikesCounter">
        <p>You have liked us {totalLikes} times so far.</p>
        <button onClick={() => setTotalLikes(totalLikes + 1)}>
          Click here to like again!
        </button>
      </div>
      <div className="CustomerInfo">
        <CustomerInfo />
      </div>
    </div>
  );
}

Entonces, vemos que el App El componente tiene un internal state-gestionado a través del useState() gancho. este state sigue contando cuántas veces al usuario le ha gustado el servicio/sitio, y es inicialally establecido en zero. Nada desafiante en lo que respecta a las aplicaciones React, ¿verdad? En el lado de la interfaz de usuario, las cosas se ven así:

El botón parece demasiado tentador para no romperlo, ¡al menos para mí! Pero antes de hacer eso, abriré mi b.rowsConsola de desarrollo de er y bórrala. Después de eso, presionaré el botón varias veces y esto es lo que veo:

Presioné el botón 19 veces y, como era de esperar, el recuento total de Me gusta es 19. La combinación de colores lo hacía really difícil de leer, así que agregué un rojo box resaltar lo principal: el <CustomerInfo /> ¡El componente se renderizó 20 veces!

Por qué 20?

Una vez cuando todo era initially renderizado, y luego, 19 veces cuando se presionó el botón. El botón cambia totalLikes, que es un pedazo de state dentro de <App /> componente y, como resultado, el componente principal se vuelve a renderizar. Y como hemos aprendido en las secciones anteriores de esta publicación, todos los componentes que contiene también se vuelven a renderizar. Esto no es deseado porque el <CustomerInfo /> El componente no cambió en el process y sin embargo contribuyó a la interpretación process.

¿Cómo podemos p?rev¿Entiendes eso?

Exactamente como dice el título de esta sección, usando el memo() función para crearate una copia “conservada” o en caché del <CustomerInfo /> componente. Con un componente memorizado, React mira sus accesorios y los compara con el prevaccesorios interesantes, y si no hay cambios, React no extract una nueva salida de “renderizado” de este componente.

Agreguemos esta línea de código a nuestro CustomerInfo.js archivo:

export const MemoizedCustomerInfo = React.memo(CustomerInfo);

¡Sí, eso es todo lo que tenemos que hacer! Ahora es el momento de usar esto en nuestro componente principal y ver si algo cambia:

import React, { useState } from "react";
import "./styles.css";
import { MemoizedCustomerInfo } from "./CustomerInfo";

export default function App() {
  const [totalLikes, setTotalLikes] = useState(0);
  return (
    <div className="App">
      <div className="LikesCounter">
        <p>You have liked us {totalLikes} times so far.</p>
        <button onClick={() => setTotalLikes(totalLikes + 1)}>
          Click here to like again!
        </button>
      </div>
      <div className="CustomerInfo">
        <MemoizedCustomerInfo />
      </div>
    </div>
  );
}

Sí, solo cambiaron dos líneas, pero de todos modos quería mostrar el componente completo. Nada cambió UI-wise, así que si pruebo la nueva versión y aprieto el botón Me gusta varias veces, obtengo esto:

Entonces, ¿cuántos mensajes de consola tenemos?

¡Sólo uno! Esto significa que, aparte del renderizado inicial, el componente no se tocó en absoluto. Imagine las ganancias de rendimiento en una really aplicación de alta escala! Vale, vale, el enlace al campo de juego de códigos que prometí es Haga clic aquí para entrar.. para replicarate En el ejemplo anterior, necesitarás importar y usar CustomerInfo en lugar de MemoizedCustomerInfo del CustomerInfo.js.

Dicho esto, las memo() isn’t magic sand that you can sprinkle everywhere and expect magical results. Overuse of memo() También puede introducir errores complicados en tu aplicación y, a veces, simplemente causar algunas actualizaciones esperadas.ates para fallar. El consejo general sobre optimización “prematura” también se aplica aquí. Primero, construye tu aplicación como te dice tu intuición; luego haz algo intensivo profiIntento ver qué partes son lentas y si parece que los componentes memorizados son la solución correcta, entonces introdúzcalos.

Diseño de componentes "inteligente"

Puse “inteligente” entre comillas porque: 1) La inteligencia es altamente subjetiva y situacional; 2) Las acciones supuestamente inteligentes a menudo tienen consecuencias desagradables. Entonces, mi consejo para esta sección es: no confíe demasiado en lo que está haciendo.

Dicho esto, una posibilidad de mejorar el rendimiento del renderizado es diseñar y colocar los componentes de forma un poco diferente. Por ejemplo, un componente secundario se puede refactorizar y mover a algún lugar superior de la jerarquía para evitar volver a renderizar. Ninguna regla dice que "el componente ChatPhotoView siempre debe estar dentro del componente Chat". En casos especiales (y estos son casos en los que tenemos evidencia respaldada por datos de que el rendimiento se está viendo afectado), doblar o romper las reglas puede actuarally ser una gran idea.

Para Concluir

Se puede hacer mucho más para optimizar Reaccionar aplicaciones en general, pero como este artículo trata sobre renderizado, he restringido el alcance de la discusión. De todos modos, espero que ahora tengas una mejor idea de lo que está sucediendo en React bajo el capó, lo que representa realmenteally es y cómo puede afectar el rendimiento de la aplicación.

A continuación, entendamos que es React Hooks?

Comparte en:
  • Ankush
    Autor
    Escribo sobre, alrededor y para el desarrollador. ecossistema. Recomendaciones, tutoriales, discusiones técnicas: ¿por qué?ateCada vez que publico, hago todo lo posible para eliminar la confusión y las tonterías, y proporcionar respuestas prácticas basadas en la experiencia personal...

Gracias a nuestros patrocinadores

Más lecturas interesantes sobre el desarrollo

Impulse su negocio

Algunas de las herramientas y servicios para ayudar a su negocio grow.
  • La herramienta de conversión de texto a voz que utiliza IA para generarate Voces realistas parecidas a las humanas.

    Intente Murf AI
  • Web scraping, proxy residencial, administrador de proxy, desbloqueador web, rastreador de motores de búsqueda y todo lo que necesita para recopilar datos web.

    Prueba Brightdata
  • Monday.com es un sistema operativo de trabajo todo en uno para ayudarlo a administrar proyectos, tareas, trabajo, ventas, CRM, operaciones, workflows, y más.

    Intente Monday
  • Intruder es un escáner de vulnerabilidades en línea que encuentra debilidades de ciberseguridad en su infraestructura, para evitar costosas filtraciones de datos.

    Intente Intruder