SkillGridAprende informática practicando

Renderizado: como el cambio se convierte en pixeles

Qué es realmente un renderizado nuevo, por qué la interfaz es función del estado, por qué las claves de las listas deciden qué fila reutiliza el navegador y por qué medir es mejor que adivinar.

14 min · 45 XP

Un contador que funciona parece magia durante mas o menos un dia. Despues agregas una lista a la pagina, las filas empiezan a comportarse de forma rara, y la magia se convierte en una pregunta: que pasa exactamente entre el clic y los nuevos pixeles?

Primero, aclaremos la palabra. Recargar significa que el navegador tira la pagina a la basura y le pide todo de nuevo al servidor: un documento nuevo, elementos nuevos, y cada pedacito de estado que tenias desaparece. Un renderizado nuevo no se parece en nada a eso. La pagina sigue, la pestana del navegador sigue, y las funciones de los componentes se ejecutan otra vez para producir una descripcion fresca de la interfaz. Nadie habla con el servidor a menos que tu codigo pida datos.

UserAppDOMreloadF5a completely new treere-renderclickonly the text that changedthe same tree, one detail updated

Por eso la gente escribe la interfaz como una funcion del estado. Tu no describes la transicion de la pantalla vieja a la nueva. Describes como deberia ser la pantalla para los datos actuales, y dejas que el framework calcule la diferencia.

function Total({ items }) {
  const sum = items.reduce((acc, item) => acc + item.price, 0);
  return <p>{sum}</p>;
}

const view = <Total items={cart} />;Dada la misma canasta, esta funcion siempre devuelve el mismo total.

Ahora el error clasico. Dibujas una lista a partir de los datos, y cada fila recibe una key estable que identifica al elemento, no su posicion.

function Rows({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

items.map((item) => <li>{item.name}</li>);La primera version le da al framework una identidad estable por fila. La segunda no le da nada.

La key es como el framework reconoce que esta fila en pantalla es el mismo elemento que aquel en los datos nuevos. Sin keys recurre a la posicion: la fila uno es la fila uno, la fila dos es la fila dos. Agrega un elemento al principio de una lista de campos de texto y los valores parecen bajar una fila, porque el navegador conservo el primer campo y solo cambio la etiqueta que tiene encima. Los datos nunca estuvieron mal. Las filas nunca se emparejaron con los elementos correctos.

Si volver a renderizar un componente es ejecutar otra vez una funcion, por que no es terriblemente lento? Porque normalmente no lo es. Una tecla puede ejecutar un punado de funciones pequenas que crean unos cientos de objetos simples, y eso es mucho mas barato que dibujar un cuadro en el navegador. Es algo que se puede permitir de una forma que hace veinte anos simplemente no se podia, y las aplicaciones modernas se construyen sobre ese hecho.

Y por eso el consejo honesto sobre la velocidad es aburrido: mide antes de optimizar. Una pagina puede volver a renderizarse miles de veces por segundo y sentirse instantanea, mientras que una sola imagen con mal tamano hace que se sienta rota. Adivinar que parte es lenta es la herramienta menos confiable que existe; el navegador ya trae perfiladores que simplemente te lo dicen.

Práctica

  1. Un contador actualiza su número al instante, la dirección en la barra del navegador no cambia y el resto de la página mantiene su posición de scroll. ¿Qué pasó?

    Pistas
    • Fíjate en la barra de direcciones y en la posición del scroll: una recarga las destruye y las vuelve a crear, un renderizado nuevo no.
    • Un renderizado nuevo pasa otra vez por las mismas funciones del componente. No le pide la página al servidor de nuevo.
  2. Un cuadro de búsqueda obtiene resultados de una API una sola vez y después los filtra localmente en cada tecla. Ordena los pasos.

    1. 1El componente calcula qué resultados coinciden con el texto actual
    2. 2Devuelve los elementos de las filas que coinciden, cada uno con un key estable
    3. 3La lista que llega se guarda como estado, así sobrevive a las siguientes ejecuciones
    4. 4El componente le pide la lista al servidor una sola vez
    5. 5El framework solo actualiza las filas cuyo contenido cambió
    Pistas
    • No se puede calcular nada antes de obtener los datos, y no se puede dibujar nada antes de calcularlo.
    • El botón no es el valor. El clic solo pide el cambio; el cambio en sí ocurre en el paso siguiente.
  3. Une cada situacion con la explicacion honesta de lo que esta pasando.

    Pistas
    • Una columna trata de un valor que cambió y la otra de lo que el navegador hace con él.
    • Pregúntate cuál de estas cosas es cierta para el botón del contador y cuál lo es para una página que se recarga.