memo permite que un componente se salte un nuevo renderizado cuando sus props son las mismas que la última vez. Envuelve un componente en memo(...) y, cuando su padre renderiza, React compara primero cada prop nueva con la vieja; si todas son iguales, reutiliza el resultado anterior en lugar de volver a llamar al componente.
Escribe en el input: va al día, y la consola muestra render SlowList solo una vez, del primer renderizado. Quita el envoltorio memo( (y su paréntesis de cierre) y vuelve a escribir: ahora cada pulsación espera 150 ms por la lista y registra un renderizado.
La sintaxis
import { memo } from 'react';
const MemoizedComponent = memo(SomeComponent, arePropsEqual?);
SomeComponentes cualquier componente de función. El estilo habitual es envolver directamente la definición:const Card = memo(function Card(props) { ... }). Darle nombre a la función interna conserva el nombre en React DevTools y en los mensajes de error.arePropsEquales opcional y rara vez hace falta (ver más abajo).- El resultado es un componente que renderizas como cualquier otro.
Por defecto React compara las props viejas y nuevas de forma superficial: revisa cada prop con Object.is. Las cadenas, números y booleanos se comparan por valor, así que title="Hi" es igual a title="Hi". Los objetos, arrays y funciones se comparan por referencia: dos objetos con el mismo contenido siguen siendo objetos distintos.
En el ejemplo de arriba, items está declarado fuera del componente, así que es el mismo array en cada renderizado, y la comparación pasa.
Los objetos y funciones nuevos anulan memo
Todo lo que se escribe como literal dentro del cuerpo del padre se vuelve a crear en cada renderizado: { name: 'Ada' }, [1, 2, 3], () => save(). Pasa uno a un componente con memo y la prop nunca es igual a la anterior.
Cada clic registra render Badge object prop pero nunca la versión con cadena. Hay tres formas de arreglar el caso del objeto:
- Pasa primitivos.
name="Ada"en lugar deuser={{ name: 'Ada' }}cuando el hijo solo necesita uno o dos campos. - Saca las constantes del componente. Un objeto que nunca cambia puede vivir a nivel de módulo, como
itemsen el primer ejemplo. - Guárdalo en caché. Envuelve en useMemo los objetos y arrays construidos a partir de props o estado, y las funciones en useCallback.
children tiene el mismo problema. <Card><p>Hello</p></Card> crea un objeto de elemento <p> nuevo en cada renderizado, así que un Card con memo que recibe children vuelve a renderizar cada vez.
Lo que memo no impide
memo solo mira las props que vienen del padre. Un componente memoizado sigue renderizando cuando:
- cambia su propio estado, mediante su propio
useStateouseReducer; - cambia un contexto que lee, mediante
useContext.
Haz clic en Unrelated y Panel se salta. Cambia el tema y renderiza, porque lee el contexto. Haz clic en Like y renderiza, porque cambió su propio estado. Ese es el comportamiento esperado: memo sirve para saltarse trabajo cuando no cambió nada de lo que depende el componente, y el contexto y el estado son cosas de las que depende.
Una función de comparación propia
El segundo argumento reemplaza la comparación superficial. Recibe las props anteriores y las siguientes y devuelve true cuando deben tratarse como iguales, lo que significa que React se salta el renderizado.
const MemoChart = memo(Chart, (prev, next) => {
return (
prev.points.length === next.points.length &&
prev.points.every((p, i) => p === next.points[i]) &&
prev.color === next.color &&
prev.onSelect === next.onSelect
);
});
Rara vez lo necesitas, y es fácil equivocarse. Si la función ignora una prop, el componente sigue mostrando el valor viejo de esa prop. Ignorar una prop de función es el peor caso: el componente que se salta sigue llamando a la función vieja, que lee estado viejo. Compara todas las props, y no hagas comprobaciones de igualdad profunda sobre datos grandes, porque entonces la comparación cuesta más que el renderizado que ahorra. Las props estables mediante useMemo y useCallback son casi siempre la mejor solución.
Comprobar que memo funciona
La comprobación más rápida es la que usa esta página: un console.log al principio del componente. Si se imprime cuando esperabas que se saltara, registra también las props y compáralas con las anteriores para encontrar la que cambió. En un proyecto real, React DevTools ayuda más: activa "Highlight updates when components render" en su configuración para ver qué componentes parpadean en cada interacción, y la pestaña Profiler graba cada renderizado y, con la opción correspondiente activada, por qué renderizó cada componente.
Dos cosas parecen un fallo de memo pero no lo son:
- El primer renderizado siempre ocurre.
memosolo se salta renderizados después de que el componente renderizó una vez con esas props. - Los builds de desarrollo pueden renderizar más. Con StrictMode, React renderiza cada componente dos veces en desarrollo para detectar código impuro. La vista previa de aquí funciona como un build de producción, así que cada línea de registro de arriba significa un renderizado real.
Cuándo usar memo
memo vale la pena cuando un componente tarda en renderizar y su padre renderiza a menudo con las mismas props para él: una lista larga o un gráfico junto a un input, una barra lateral dentro de una página que se actualiza cada segundo. Para componentes que renderizan rápido, o cuyas props cambian igual cada vez, agrega una comparación y no aporta nada. Antes de memoizar, mira si puedes reorganizar en su lugar, bajando el estado o pasando JSX como children, como se muestra en la página de renderizado.
El React Compiler 1.0, si tu proyecto lo usa, memoiza automáticamente los componentes y sus props al hacer el build, lo que hace innecesarias la mayoría de las llamadas manuales a memo. Sin él, memo funciona exactamente como se describe aquí y sigue siendo habitual en el código de React.
Preguntas frecuentes
¿Qué hace React.memo?
Devuelve una versión memoizada de un componente. Cuando el padre renderiza, React compara las props nuevas con las anteriores y se salta el renderizado del componente si cada prop es igual según Object.is.
¿Por qué mi componente con memo se sigue renderizando?
Normalmente porque una prop es un objeto, array o función nuevo creado durante el renderizado del padre, así que nunca es igual al anterior. El componente también renderiza cuando cambia su propio estado o cuando cambia un contexto que lee, con memo o sin él.
¿Cuál es la diferencia entre React.memo y useMemo?
memo envuelve un componente y se salta su renderizado. useMemo es un hook dentro de un componente que guarda en caché un valor calculado. A menudo trabajan juntos: useMemo mantiene estable una prop de objeto para que memo pueda saltar el renderizado.
¿Debo envolver todos los componentes en memo?
No. La mayoría de los renderizados son baratos, y la comparación de props tiene su propio costo. Úsalo para componentes que tardan en renderizar y que a menudo reciben las mismas props.
¿memo funciona con children?
Rara vez. El JSX pasado como children es un objeto nuevo en cada renderizado, así que un componente con memo que recibe children casi siempre vuelve a renderizar.