Aprendiendo a dominar el uso de Callback Hook de React
Publicado: 2022-04-27No es ningún secreto que React.js se ha vuelto muy popular en los últimos años. Ahora es la biblioteca de JavaScript elegida por muchos de los jugadores más destacados de Internet, incluidos Facebook y WhatsApp.
Una de las principales razones de su auge fue la introducción de ganchos en la versión 16.8. Los ganchos de React le permiten aprovechar la funcionalidad de React sin escribir componentes de clase. Ahora los componentes funcionales con ganchos se han convertido en la estructura de referencia de los desarrolladores para trabajar con React.
En esta publicación de blog, profundizaremos en un gancho específico, useCallback
, porque toca una parte fundamental de la programación funcional conocida como memorización. Sabrá exactamente cómo y cuándo utilizar el useCallback
y aprovechar al máximo sus capacidades de mejora del rendimiento.
¿Listo? ¡Vamos a sumergirnos!
¿Qué es la memorización?
La memorización es cuando una función compleja almacena su salida para que la próxima vez se llame con la misma entrada. Es similar al almacenamiento en caché, pero a un nivel más local. Puede omitir cualquier cálculo complejo y devolver el resultado más rápido, ya que ya está calculado.
Esto puede tener un efecto significativo en la asignación de memoria y el rendimiento, y esa tensión es lo que el useCallback
pretende aliviar.
UseCallback de React vs useMemo
En este punto, vale la pena mencionar que useCallback
se combina muy bien con otro gancho llamado useMemo
. Hablaremos de ambos, pero en este artículo nos centraremos en useCallback
como el tema principal.
La diferencia clave es que useMemo
devuelve un valor memorizado, mientras que useCallback
devuelve una función memorizada. Eso significa que useMemo
se usa para almacenar un valor calculado, mientras que useCallback
devuelve una función a la que puede llamar más adelante.
Estos ganchos le devolverán una versión en caché a menos que cambie una de sus dependencias (por ejemplo, estado o accesorios).
Echemos un vistazo a las dos funciones en acción:
import { useMemo, useCallback } from 'react' const values = [3, 9, 6, 4, 2, 1] // This will always return the same value, a sorted array. Once the values array changes then this will recompute. const memoizedValue = useMemo(() => values.sort(), [values]) // This will give me back a function that can be called later on. It will always return the same result unless the values array is modified. const memoizedFunction = useCallback(() => values.sort(), [values])
El fragmento de código anterior es un ejemplo artificial, pero muestra la diferencia entre las dos devoluciones de llamada:
-
memoizedValue
se convertirá en la matriz[1, 2, 3, 4, 6, 9]
. Mientras la variable de valores permanezca, también lo harámemoizedValue
y nunca se volverá a calcular. -
memoizedFunction
será una función que devolverá la matriz[1, 2, 3, 4, 6, 9]
.
Lo bueno de estas dos devoluciones de llamada es que se almacenan en caché y permanecen hasta que cambia la matriz de dependencia. Esto significa que en un renderizado, no se recolectará basura.
twittearRenderizar y reaccionar
¿Por qué es importante la memorización cuando se trata de React?
Tiene que ver con cómo React representa sus componentes. React usa un DOM virtual almacenado en la memoria para comparar datos y decidir qué actualizar.
El DOM virtual ayuda a React con el rendimiento y mantiene su aplicación rápida. De manera predeterminada, si algún valor en su componente cambia, todo el componente se volverá a procesar. Esto hace que React sea "reactivo" a la entrada del usuario y permite que la pantalla se actualice sin recargar la página.
No desea renderizar su componente porque los cambios no afectarán ese componente. Aquí es donde resulta útil la memorización mediante useCallback
y useMemo
.
Cuando React vuelve a renderizar su componente, también recrea las funciones que ha declarado dentro de su componente.
Tenga en cuenta que al comparar la igualdad de una función con otra función, siempre serán falsas. Como una función también es un objeto, solo se igualará a sí misma:
// these variables contain the exact same function but they are not equal const hello = () => console.log('Hello Matt') const hello2 = () => console.log('Hello Matt') hello === hello2 // false hello === hello // true
En otras palabras, cuando React vuelve a renderizar su componente, verá todas las funciones declaradas en su componente como funciones nuevas.
Esto está bien la mayor parte del tiempo, y las funciones simples son fáciles de calcular y no afectarán el rendimiento. Pero las otras veces que no desea que la función se vea como una función nueva, puede confiar en useCallback
para que lo ayude.
Podría estar pensando: "¿Cuándo no querría que una función se viera como una nueva función?" Bueno, hay ciertos casos en los que useCallback
tiene más sentido:
- Está pasando la función a otro componente que también está memorizado (
useMemo
) - Su función tiene un estado interno que necesita recordar
- Su función es una dependencia de otro enlace, como
useEffect
por ejemplo
Beneficios de rendimiento de React useCallback
Cuando useCallback
se usa correctamente, puede ayudar a acelerar su aplicación y evitar que los componentes se vuelvan a procesar si no es necesario.

Digamos, por ejemplo, que tiene un componente que obtiene una gran cantidad de datos y es responsable de mostrar esos datos en forma de tabla o gráfico, como este:
Suponga que el componente principal para el componente de su visualización de datos se vuelve a renderizar, pero las propiedades o el estado modificados no afectan a ese componente. En ese caso, probablemente no quiera o necesite volver a renderizarlo y recuperar todos los datos. Evitar esta nueva representación y recuperación puede ahorrar el ancho de banda de su usuario y proporcionar una experiencia de usuario más fluida.
Inconvenientes de React useCallback
Aunque este gancho puede ayudarlo a mejorar el rendimiento, también tiene sus inconvenientes. Algunas cosas a considerar antes de usar useCallback
(y useMemo
) son:
- Recolección de basura: las otras funciones que aún no están memorizadas serán descartadas por React para liberar memoria.
- Asignación de memoria: similar a la recolección de basura, cuantas más funciones memorizadas tenga, más memoria se requerirá. Además, cada vez que usa estas devoluciones de llamada, hay un montón de código dentro de React que necesita usar aún más memoria para proporcionarle la salida en caché.
- Complejidad del código: cuando comienza a envolver funciones en estos ganchos, aumenta inmediatamente la complejidad de su código. Ahora requiere una mayor comprensión de por qué se utilizan estos ganchos y la confirmación de que se utilizan correctamente.
Ser consciente de las trampas anteriores puede ahorrarle el dolor de cabeza de tropezar con ellas usted mismo. Cuando considere emplear useCallback
, asegúrese de que los beneficios de rendimiento superen los inconvenientes.
Reaccionar useCallback Ejemplo
A continuación se muestra una configuración simple con un componente de botón y un componente de contador. El contador tiene dos partes de estado y genera dos componentes de botón, cada uno de los cuales actualizará una parte separada del estado de los componentes de contador.
El componente Button tiene dos accesorios: handleClick
y name. Cada vez que se representa el Botón, se registrará en la consola.
import { useCallback, useState } from 'react' const Button = ({handleClick, name}) => { console.log(`${name} rendered`) return <button onClick={handleClick}>{name}</button> } const Counter = () => { console.log('counter rendered') const [countOne, setCountOne] = useState(0) const [countTwo, setCountTwo] = useState(0) return ( <> {countOne} {countTwo} <Button handleClick={() => setCountOne(countOne + 1)} name="button1" /> <Button handleClick={() => setCountTwo(countTwo + 1)} name="button1" /> </> ) }
En este ejemplo, cada vez que haga clic en cualquiera de los botones, verá esto en la consola:
// counter rendered // button1 rendered // button2 rendered
Ahora, si aplicamos useCallback
a nuestras funciones handleClick
y envolvemos nuestro Button en React.memo
, podemos ver lo que nos proporciona useCallback
. React.memo
es similar a useMemo
y nos permite memorizar un componente.
import { useCallback, useState } from 'react' const Button = React.memo(({handleClick, name}) => { console.log(`${name} rendered`) return <button onClick={handleClick}>{name}</button> }) const Counter = () => { console.log('counter rendered') const [countOne, setCountOne] = useState(0) const [countTwo, setCountTwo] = useState(0) const memoizedSetCountOne = useCallback(() => setCountOne(countOne + 1), [countOne) const memoizedSetCountTwo = useCallback(() => setCountTwo(countTwo + 1), [countTwo]) return ( <> {countOne} {countTwo} <Button handleClick={memoizedSetCountOne} name="button1" /> <Button handleClick={memoizedSetCountTwo} name="button1" /> </> ) }
Ahora, cuando hagamos clic en cualquiera de los botones, solo veremos el botón en el que hicimos clic para iniciar sesión en la consola:
// counter rendered // button1 rendered // counter rendered // button2 rendered
Hemos aplicado memorización a nuestro componente de botón, y los valores prop que se le pasan se ven como iguales. Las dos funciones handleClick
se almacenan en caché y React las verá como la misma función hasta que cambie el valor de un elemento en la matriz de dependencias (por ejemplo, countOne
, countTwo
).
Resumen
A pesar de lo interesantes que son useCallback
y useMemo
, recuerde que tienen casos de uso específicos: no debe envolver todas las funciones con estos ganchos. Si la función es computacionalmente compleja, una dependencia de otro enlace o un apoyo pasado a un componente memorizado son buenos indicadores de que tal vez desee alcanzar useCallback
.
¡Esperamos que este artículo lo haya ayudado a comprender esta funcionalidad avanzada de React y lo haya ayudado a ganar más confianza con la programación funcional en el camino!