Original article: Caching in React – How to Use the useMemo and useCallback Hooks

A medida que te vuelves más proficiente programando en React, el rendimiento se convertirá en un punto focal importante en tu proceso de desarrollo.

Como con cualquier herramienta o metodología de programación, el caché juega un rol enorme cuando se trata de optimizar aplicaciones de React.

Caché en React típicamente va por el término de memoización. Se usa para mejorar el rendimiento al reducir la cantidad de veces que un componente se renderiza debido al estado o a las mutaciones del prop.

React provee dos APIs para la caché: useMemo y useCallback. useCallback es un hook que memoiza una función, mientras que useMemo es un hook que memoiza un valor. Estos dos hooks son frecuentemente usados en conjunción con la API Context para mejorar aún más la eficiencia.

Aquí hay una lista básica de tópicos que estaremos cubriendo en este artículo:

  1. Comportamiento predeterminado de almacenamiento en caché en React.
  2. El hook useMemo.
  3. El hook useCallback.

Para seguir adelante, necesitarás un entendimiento bastante bueno de React y de componentes con estado.

Comportamiento predeterminado de almacenamiento en caché en React

Por defecto, React usa una técnica llamada "comparación superficial" para determinar si un componente debería ser re-renderizado. Esto significa básicamente que si las propiedades o estado de un componente no han cambiado, React asumirá que la salida del componente tampoco ha cambiado y no lo re-renderizará.

Mientras que este comportamiento de almacenamiento en caché predeterminado es muy efectivo por sí mismo, no siempre es suficiente para optimizar componentes complejos que requieren una gestión de estado avanzado.

Para lograr más control sobre la caché de tus componentes y el comportamiento de la renderización, React ofrece los hooks useMemo y useCallback.

Caché en React con el hook useMemo

useMemo es útil cuando necesitas hacer un cálculo costoso para devolver un valor, y quieres asegurarte que el cálculo solamente se ejecute cuando sea necesario. Al memoizar el valor usando useMemo, puedes asegurarte que el valor se ejecute solamente cuando sus dependencias cambien.

En un componente de React, puedes tener múltiples propiedades que forman tu estado. Si una pieza del estado cambia, el cual no tiene nada que ver con nuestro valor costoso, ¿por qué volver a ejecutarlo si este no ha cambiado?

Aquí hay un bloque de código de ejemplo que refleja una implementación básica de useMemo:  

import React, { useState, useMemo } from 'react';

function Example() {
	const [txt, setTxt] = useState(“Algo de texto”);
	const [a, setA] = useState(0);
	const [b, setB] = useState(0);
    
	const sum = useMemo(() => {
	console.log('Calculando suma...');
	  return a + b;
	}, [a, b]);

	return (
	  <div>
		<p>Texot: {txt}</p>
		<p>a: {a}</p>
		<p>b: {b}</p>
		<p>sum: {sum}</p>
		<button onClick={() => setTxt(“Nuevo Texto!”)}>Escribir Texto</button>
		<button onClick={() => setA(a + 1)}>Incrementar a</button>
		<button onClick={() => setB(b + 1)}>Incrementar b</button>
	  </div>
	);
}

En nuestro componente Ejemplo de arriba, asumimos que la función sum() ejecuta un cálculo costoso. Si el estado txt se actualiza, React va a re-renderizar nuestro componente, pero como memoizamos el valor devuelto de sum, esta función no se ejecutará esta vez nuevamente.

La única vez que la función sum() se ejecutará es si el estado a o b ha sido mutado (cambiado). Este una mejora excelente sobre el comportamiento predeterminado, el cual re-ejecutará este método sobre cada re-renderizado.

Caché en React con el hook useCallback

useCallback es útil cuando necesitas pasar una función como una propiedad a un componente hijo, y quieres asegurarte que la referencia de la función no cambia innecesariamente. Al memoizar la función usando useCallback, puedes asegurarte que la referencia de la función sigue siendo siempre el mismo y cuando sus dependencias no cambien.

Sin entrar demasiado en profundidad en las referencias de función de JavaScript, vamos a ver cómo pueden afectar la renderización de tu aplicación de React. Cuando una referencia de una función cambia, cualquier componente hijo que recibe la función como una propiedad se re-renderizará, inclusive si la lógica de la función misma no ha cambiado.

Esto se debe a que, como ya mencionamos, React hace una comparación superficial de los valores de las propiedades para determinar si un componente debería re-renderizarse, y una nueva referencia de una función siempre será considerada como un valor diferente al anterior.

En otras palabras, el simple acto de re-declarar una función (inclusive la misma función exacta), causa que la referencia cambie, y causará que el componente hijo que recibe la función como una propiedad se renderice innecesariamente.

Aquí hay un bloque de código de ejemplo que refleja una implementación básica de useCallback:

import React, { useState, useCallback } from 'react';

function ChildComponent({ onClick }) {
  console.log('ChildComponent se renderiza');
  return (
	<button onClick={onClick}>Hazme clic</button>
  );
}

function Example() {
  const [count, setCount] = useState(0);
  const [txt, setTxt] = useState(“Algo de texto…”);
  const incrementCount = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, [setCount]);

  return (
	<div>
	  <p>Texto: {txt}</p>
	  <p>Contador: {count}</p>
	  <button onClick={setTxt}>Escribir Texto</button>
	  <button onClick={setCount}>Incrementar</button>
	  <ChildComponent onClick={incrementCount} />
    </div>
  );
}

Como puedes ver en el ejemplo de arriba, pasamos el método incrementCount en vez del método setCount al componente hijo. Esto se debe a que incrementCount es memoizado, y cuando ejecutamos nuestro método setTxt, no hará que el componente hijo innecesariamente  re-renderice.

La única manera que nuestro componente hijo se vuelva a renderizar en este ejemplo es si el método setCount se ejecuta, porque le pasamos como un parámetro de dependencia a nuestra memoización useCallback.

Conclusión

Almacenar en la caché es una técnica importante para optimizar aplicaciones de React. Al reducir re-renderizados innecesarios, el almacenamiento en caché puede ayudar en mejorar el rendimiento y eficiencia de tu aplicación.

React provee un comportamiento de almacenamiento en caché predeterminado al usar un DOM virtual para comparar los cambios en el estado y las props, y actualizar los componentes solamente después de que una comparación superficial refleje cambios. Este es una gran técnica de optimización que es suficiente en muchos escenarios, pero a veces se desea más control detallado.

Los hooks useMemo y useCallback fueron creados para alcanzar este control detallado.

useMemo se usa para memoizar los resultados de una llamada de función, y es útil cuando la función es costosa para ejecutar y el resultado no cambia con frecuencia.

useCallback se usa para memoizar la referencia actual de una función en vez del valor devuelto, y se usa cuando la función se pasa como una prop a componentes hijos que pueden causar re-renderizados innecesarios.

¿Quieres aprender más? Para aprender más visita mi Blog OhMyCrawl para más consejos de programación para SEO.