Coffee bytes

Blog de desarrollo web con Python y Javascript

Eduardo Zepeda

React memo y useCallback para evitar renderizaciones

El martes, 10 de agosto de 2021

por Eduardo Zepeda

Tiempo de lectura: 3 minutos

Podemos usar react memo y useCallback para evitar que un componente se renderice, inútilmente, múltiples veces por medio de la memoización. Si no sabes que es memoización o no entiendes para que sirven los componentes de react, useCallback y memo, tengo una entrada donde explico useCallback, useMemo y memo, para que sirven, así como sus diferencias y similitudes.

Empecémos nuestro ejemplo con el siguiente componente:

import ChildComponent from './ChildComponent'

const MyComponent = () => {
  // callback va a ser diferente cada vez que este componente se renderice
  const callback = () => {
    return 'Texto del componente hijo'
  };
  return <ChildComponent callback={callback} />;
}

export default MyComponent

Cada vez que MyComponent se renderice, React creará una función nueva llamada callback, y se la pasará a ChildComponent, que se renderizará a su vez.

El primer paso será memoizar el componente hijo, ChildComponent, para que se mantenga constante mientras sus props no cambien. Para hacerlo basta con pasarle el componente a la función memo y exportarlo.

import { memo } from "react";

const ChildComponent = ({ callback }) => {
  const textoDelComponenteHijo = callback();
  return <div>{textoDelComponenteHijo}</div>;
};

export default memo(ChildComponent)

Como te mencioné anteriormente, cada vez que React renderiza un componente se crearán nuevamente sus funciones internas, convirtiéndose en un prop diferente para cada componente hijo que las reciba.

Para evitar que los props cambien, tenemos que memoizar la función que memo está recibiendo como prop. ¿Cómo? Pues usando el hook useCallback de React

import ChildComponent from './ChildComponent'
import {useCallback} from 'react'

const MyComponent = ({ prop }) => {
  const callback = useCallback(() => {
    return 'Result'
  },[])
  return <ChildComponent callback={callback} />;
}

export default MyComponent

Ahora la función callback no cambiará cada que se renderice MyComponent, se mantendrá constante. Por lo anterior, el componente memoizado, ChildComponent, recibirá como prop la misma función, siempre, evitando su re-renderización cada que MyComponent cambie.

Probando el efecto de React memo y useCallback

¿Aún no te queda claro? Checa este ejemplo en un sandbox.

En el siguiente sandbox, observa como el ChildComponent tiene un método console.log que escribe en terminal cada vez que el componente se renderiza. Si escribes en el input notarás que ChildComponent no se está renderizando con cada tecla presionada.

¿Por qué? Primero, estamos usando memo en el ChildComponent para evitar renderizaciones. Segundo, estamos usando useCallback para evitar que la función de MyComponent cambie, por lo que memo recibe siempre el mismo prop.

Ahora prueba lo siguiente en este sandbox:

Remueve únicamente la función memo del ChildComponent y escribe en el input. ChildComponent se re-renderizará con cada nueva tecla presionada. Un mensaje nuevo en terminal aparecerá por cada renderización.

// ChildComponent.js
export default ChildComponent;

En cambio, si remueves el hook useCallback, sin remover memo, ChildComponent se re-rendizará igualmente con cada tecla presionada. Esto debido a que con cada pulsación, MyComponent se re-renderiza y la función callback se crea nuevamente, al ser una nueva función, memo vuelve a renderizar el componente.

// MyComponent.js
const callback = () => {
    return "Texto del componente hijo";
  };

Pon atención a la terminal para que aprecies las renderizaciones.

Por otro lado, si remueves tanto memo como useCallback, sucederá lo mismo.

Si quieres profundizar más en el tema encontré un excelente video de youtube donde lo explican bastante bien.

Presume lo que aprendiste en redes

Únete a mi comunidad de lectores

Recibe contenido como este por correo electrónico, una vez por semana, de manera totalmente gratuita.

* Campo obligatorio