hand Inicio
hand JSBloqs
hand GutenBloqs

Qué es y cómo utilizar el React hook useCallback y el useMemo

useCallback permite memorizar funciones, lo cual es imprescindible en casos concretos

Optimizar el código

El useCallback junto con el useMemo son hooks que nos permiten optimizar nuestra aplicación

Es decir, con useCallback estamos optimizando, y aquí siempre aplica una norma general:

  • Por defecto nunca hay que optimizar nada, solo cuando nos surja la necesidad

Por lo tanto, si nunca te has cruzado con estos dos hooks es porque nunca has tenido la necesidad de optimizar tu código, o quizá porque nunca has pensado que fuera necesario

Si no es necesario, no optimices por optimizar

Si no sabes si es necesario, ejecuta tu aplicación en los dispositivos más antiguos que tus usuarios puedan utilizar, y allí podrás valorarlo

Y si tienes claro que quieres optimizar, vamos a ver las diferencias entre useMemo y useCallback

useMemo vs useCallback

En los dos casos, los dos hooks nos permiten memorizar elementos para evitar estar recalculándolos a cada rerenderizado

La diferencia es sutil pero importante:

  • useCallback nos memoriza la función
  • useMemo nos memoriza la función y el argumento, es decir nos memoriza el valor

Puede parecer que sirven para más o menos lo mismo, pero difieren bastante por una sencilla razón:

Normalmente, lo "costoso" será calcular el valor, no la función, por lo que useCallback dificilmente proporcionará una optimización significativa

Por lo tanto, lo suyo será memorizar el cálculo de un valor concreto con useMemo, allí es donde optimizaremos el código simplemente evitando repetir el cálculo

Para mostrar cómo funciona useMemo (y useCallback), mejor con un ejemplo muy simple (la sintaxis es la misma que con useEffect)

jsx
import React, { useState, useMemo, useCallback } from 'react'

export const App = () => {
const [counter1, setCounter1] = useState(1)
const [counter2, setCounter2] = useState(1)
const [counter3, setCounter3] = useState(1)

const set1 = () => setCounter1(prev => prev + 1)
const set2 = useMemo(() => setCounter2(prev => prev + 1), [])
const set3 = useCallback(() => setCounter2(prev => prev + 1), [])

return (
<div>
<div>
<button onClick={set1}>Contador {counter1}</button>
</div>
<div>
<button onClick={set2}>Contador useMemo {counter2}</button>
</div>
<div>
<button onClick={set3}>Contador useCallback {counter3}</button>
</div>
</div>
)
}

export default App // esto es para codesandbox

Aquí puedes ver dos cosas:

  • El contador con el useMemo empieza en 2, porque ya ha ejecutado una suma

  • Cuando aprietas el botón, el valor de useMemo no se mueve porque el valor no se recalcula

  • Con el useCallback el valor se calcula como esperarías ya que sólo se ha memorizado la función

useCallback para evitar rerenders

Entonces, si el useCallback no sirve para optimizar de forma significativa, para qué se utiliza?

Para evitar rerenders específicos

Lo vemos mejor con este código

jsx
import React, { useState, useCallback, useEffect } from 'react'

export const App = () => {
const [counter1, setCounter1] = useState(1)
const [counter2, setCounter2] = useState(1)

const sum1 = () => setCounter1(prev => prev + 1)
const sum2 = useCallback(() => setCounter2(prev => prev + 1), [])

useEffect(() => {
console.log('repainted')
setCounter1(prev => prev + 1)
}, [sum2])

return (
<div>
<div>
<button onClick={sum1}>{counter1}</button>
</div>
<div>
<button onClick={sum2}>{counter2}</button>
</div>
</div>
)
}

export default App // esto es para codesandbox

Este código en sí mismo no hace nada, pero nos sirve para entender el valor de useCallback

Es complicado saber cuándo una función (en este caso sum1 y sum2) se vuelven a recalcular

Una manera de verlo es con el useEffect, poniéndo como dependencias a sum1 y sum2

En el ejemplo verás como solo le he puesto el sum2, y puedes ver como nunca se ejecuta el console.log

Esto es así porque la constante sum2 sólo se calcula una vez y no se vuelve a recalcular

Y esto es así gracias a useCallback

Por contra, el valor sum1 sí se vuelve a recalcular cada vez que el componente <App> vuelve a rerenderizarse

Cómo puedes verlo?

Añade sum1 como dependencias al useEffect, y verás como de repente entras en un loop infinito (quita la dependencia pronto o el navegador se te bloqueará) ya que la función se recalcula y vuelve a ejecutar el useEffect que cambia el estado y vuelve a rerenderizar <App> que a su vez vuelve a recalcular sum1 etc etc etc

draw of me

Hola, tienes en mente desarrollar una web?

Si quieres, te ayudo

11ty para webs ultra-rápidaseleventy js
Gatsby para webs complejasgatsby js
WordPress para webs para el usuario finalwordpress

Escríbeme

Lista de correo: escribo algo de tanto en cuanto