Mejorando el Rendimiento en React: memo y su impacto en tus Aplicaciones

Descubre cómo optimizar el rendimiento de tus aplicaciones React utilizando la poderosa herramienta 'React.memo'. Aprende cómo esta característica puede impactar positivamente en la eficiencia y velocidad de tus componentes, permitiéndote construir interfaces más rápidas y reactivas.

Mejorando el Rendimiento en React: memo y su impacto en tus Aplicaciones
Photo by NASA / Unsplash

Hoy es fin de semana, venimos con ganas porque toca descansar un poco 🥳. Durante la reunión de standup del miércoles, surgió un tema crucial: mejorar el rendimiento de nuestros componentes, con especial atención en uno de ellos.

Aunque estamos obteniendo buenos puntajes en Lighthouse y PageSpeed hemos notado un problema en uno de nuestros componentes más utilizados: nuestro Hero Card está teniendo re-renders adicionales de manera innecesaria y esto afecta al performance en general. Esto es extraño, ya que el componente utiliza props estáticos, lo que debería evitar cualquier afectación en el rendimiento, aunque React Developer Tools opina lo contrario.

Solía ir directo al código, pero ya no soy el trainee del 2018, he aprendido que leer la documentación es algo esencial, así que tenemos que invertir tiempo en comprender las herramientas que utilizamos en nuestro día a día, con la finalidad de escribir un mejor código sólido y principalmente eficiente.

Después de un rato de estar leyendo la sección de Skipping Re-Rendering encontré que la solución no iba a ser la utilización de los hooks de memoization como useCallback o useMemo. Los props son estáticos, el problema de renderizado viene de más arriba, lo ideal es optimizar todo pero vamos por un problema a la vez, podemos ajustar nuestro componente y hacer que deje de renderizarse entre cada actualización de la página de inicio. Y aquí es donde memo entra en escena y hace su magia.

In the process of this picture I accidentally fumigated my whole bedroom. Next time I should definitely do this outside...
Photo by Julius Drost / Unsplash

Este es el componente actualmente, no hay magia negra detrás. Pero no está completamente optimizado.

import React from 'react';

const HeroCard = ({ name, power, image }) => {
  return (
    <div className="hero-card">
      <img src={image} alt={name} />
      <h2>{name}</h2>
      <p>{power}</p>
    </div>
  );
};

export default HeroCard;

Según la documentación oficial, memo es una implementación de la optimización de memorización en React. La optimización de memorización es una técnica que permite evitar re-renderizar componentes cuando las propiedades (props) que reciben no han cambiado. En situaciones donde un componente recibe las mismas props en múltiples renderizaciones, React puede utilizar la memoria caché del resultado anterior y reutilizarlo, evitando así procesos de renderizado innecesarios y mejorando el rendimiento general de la aplicación.

Memo en sí es un componente de orden superior o higher-order component, abreviado como HOC. Este retorna una versión optimizada del componente que envuelve. Al ser un HOC no altera el componente original, sino que crea una nueva instancia de él con la capacidad de memorizar sus resultados.

Ahora que ya sabemos que hace, cómo lo utilizamos? Para esto es la siguiente sección. Memo recibe dos parámetros (referencia) el primero es el componente al que queremos aplicar la optimización y el segundo es una función opcional que acepta dos argumentos (prevProps y newProps) con los que podremos aplicar lógica y decidir si React necesita renderizar nuevamente, esto lo logramos retornando un valor booleano en esta función, si es false el componente se renderizará de nuevo. Esta función es opcional y rara vez necesaria, ya que memo por defecto hace la comparación de los prevProps y los newProps para determinar si debe de hacer un re-renderizado, o no.

Para nuestro caso solo bastó retornar el componente utilizando memo ya que todos los props recibidos son valores primitivos (no hay funciones, arrays o objetos), por lo tanto la comparación de los prevProps y newProps que React.memo hace con Object.is por default, funcionará.

Aquí la optimización del componente:

import React from 'react';

const HeroCard = React.memo(({ name, power, image }) => {
  return (
    <div className="hero-card">
      <img src={image} alt={name} />
      <h2>{name}</h2>
      <p>{power}</p>
    </div>
  );
});

export default HeroCard;

Detrás de escena se hace lo siguiente: Si estas props son referencialmente iguales a las props anteriores, React.memo evitará el re-renderizado y utilizará el resultado memorizado previo.

function areEqual(prevProps, newProps) {
  // Comparación usando Object.is para las props individuales
  const nameEqual = Object.is(prevProps.name, newProps.name);
  const powerEqual = Object.is(prevProps.power, newProps.power);
  const imageEqual = Object.is(prevProps.image, newProps.image);

  // Retorna true si todas las props son iguales, evitando el re-renderizado
  return nameEqual && powerEqual && imageEqual;
}

En resumen, React.memo es una poderosa herramienta de optimización que puede mejorar significativamente el rendimiento de tus componentes React. Al utilizar memo de manera estratégica y en combinación con otras técnicas de optimización, puedes lograr una aplicación más eficiente y una experiencia de usuario más fluida.

Es importante recordar que memo no es una solución única para todos los componentes y situaciones. Debe usarse con prudencia y aplicarse a componentes que reciben props estáticas o que tienen pocos cambios en sus propiedades. Para componentes que dependen del estado interno o que tienen lógica más compleja, otras técnicas de optimización pueden ser más apropiadas.

En este post, hemos explorado qué es React.memo, cómo funciona y cómo se utiliza para optimizar componentes. Espero que esta información te sea útil en tus proyectos y te ayude a crear aplicaciones más rápidas y eficientes con React.

Gracias por leer, happy coding! :)