Uso del gancho useCallback en React - Guía para desarrolladores

React tiene muchos hooks incorporados que permiten a los componentes funcionales conectarse al ciclo de vida del componente y realizar diferentes operaciones. Está el useState hook, useEffect hook, useLayoutEffect hook y muchos más. En este artículo, veremos el hook useCallback. Aprenderemos sobre la función de este hook, su relevancia, un caso de uso común para él, y también lo compararemos con el hook useMemo.

Pruebe Memberstack gratis
25 de marzo de 2022
ÍNDICE
Dillion Megida

¿Qué es el hook useCallback en React?

El hook useCallback devuelve una función callback memoizada. La memoización es una técnica de optimización en el desarrollo de programas que almacena algún valor calculado en memoria y al que se puede acceder sin tener que volver a calcular ese valor.

Piensa en la memoización como una caché, de forma que mientras las entradas no cambien, se utiliza el valor almacenado en caché. Pero si las entradas cambian, el valor se vuelve a calcular.

Esta función callback del hook useCallback sólo cambia cuando cambian las dependencias especificadas de las que depende la función. Aquí está la sintaxis:


const func = useCallback((args) => {
  // algo de código aquí
}, [dependencias])

La matriz de dependencias especifica de qué depende este gancho. Cuando alguna de las dependencias cambia, el gancho vuelve a declarar la función y la almacena en caché.

¿Por qué necesitamos el gancho useCallback?

En general, la memoización es una gran manera de mejorar la velocidad del programa, y mejorar la experiencia del usuario al evitar volver a calcular los mismos valores una y otra vez. El hook useCallback nos ayuda a conseguir esto en componentes funcionales.

Con este gancho, podemos guardar funciones caras (funciones lentas, o funciones que utilizan muchos recursos) en memoria, y sólo tendremos que ejecutarlas cuando lo necesitemos.

Ejemplo/Uso del gancho useCallback

Evitar los nuevos cálculos debidos a la igualdad referencial

La razón más común por la que querrías usar este hook es para evitar problemas de igualdad referencial. Y esto se encuentra en los objetos. En JavaScript, los objetos, por muy similares que sean no son iguales entre sí porque tienen referencias diferentes.

Esta desigualdad en las referencias es muy común cuando se utiliza una función como dependencia, por ejemplo, en un gancho useEffect. Esto puede causar que el hook useEffect se dispare cuando no lo esperas. Veamos algo de código React para entenderlo mejor.

Supongamos que tenemos el siguiente proyecto.


// src/components/product-list.js

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

export default function ProductList({ getProducts }) => {
  const [products, setProducts] = useState([])

  useEffect(() => {
    setProducts(getProducts())    
  }, [getProducts])

  return (...) // display the products on the UI
}

// src/App.js

import React from 'react'
import ProductList from './components/product-list

export default function App() {
  const [query, setQuery] = useState("")
  const [number, setNumber] = useState(0)

  const getProducts = () => {
    // some API call here, which uses the query state
  }

  return (
    <div>
      {/* <input /> component here which updates the query state */}
      <ProductList getProducts={getProducts} />
    </div>
  ) 
}

Este proyecto básico tiene dos componentes: el componente ProductList que toma una función getProduct prop y el componente App.

La función getProduct se pasa desde el componente App al componente ProductList, que llama a la función en un gancho useEffect, actualiza el estado de los productos y muestra el valor devuelto en la interfaz de usuario. La función getProduct es también una dependencia para el gancho useEffect, de modo que la función sólo se llama cuando cambia.

Se supone que esta función getProduct realiza una llamada a la API (que podría ser lenta) cuando es evocada. Aquí está el problema con esta configuración.

En React, cuando el estado de un componente cambia, el componente se vuelve a renderizar, cada valor se vuelve a calcular y cada declaración se vuelve a declarar. Esto significa que cuando el estado de consulta cambia:

  • la función getProducts se vuelve a declarar, y la función getProducts en el estado anterior NO ES IGUAL a la función getProducts en el nuevo estado (porque en JavaScript. los objetos por muy similares que sean no son iguales entre sí)
  • en el componente ProductList , la función getProducts se vuelve a ejecutar porque el gancho useEffect cree que la dependencia getProducts ha cambiado

Esto es lo que queremos. La consulta cambia, se obtiene un nuevo conjunto de productos y se muestra en pantalla. Pero, ¿y si cambia el estado de los números? Ocurre lo mismo. La función get products se vuelve a declarar, la función get products se vuelve a ejecutar de nuevo en el componente Lista de productos.

Como forma de mejorar esto, queremos optimizar este componente para "guardar" la función get products y no tener que hacer llamadas a la API cada vez que cambie el estado. La única vez que queremos hacer una nueva llamada a la API es si cambia el estado de la consulta, para poder obtener un nuevo conjunto de productos.

Podemos mejorar esto con el gancho useCallback así:


// src/App.js

import React, { useCallback } from 'react'
import ProductList from './components/product-list

export default function App() {
  const [query, setQuery] = useState("")
  const [number, setNumber] = useState(0)

  const getProducts = useCallback(() => {
    // some API call here, which uses the query state
  }, [query])

  return (
    <div>
      {/* <input /> component here which updates the query state */}
      <ProductList getProducts={getProducts} />
    </div>
  ) 
}

Al memorizar la función getProducts, no se vuelve a declarar al volver a renderizar cuando cambia el estado del número. Esto significa que la referencia permanece igual en el gancho useEffect del componente List, por lo que el gancho useEffect no se activa.

Al pasar una dependencia de consulta, la función getProducts se volverá a declarar cuando cambie el estado de la consulta, y también se activará el gancho useEffect, que es justo lo que queremos.

¿Cuándo no se debe utilizar el gancho useCallback?

No deberías usar useCallback para resolver todos los problemas de igualdad de referencias. Sí, parece una buena solución para evitar redeclaraciones todo el tiempo, pero una cosa a tener en cuenta aquí es que la memoización es una técnica que implica guardar algunos datos en la memoria. Memoizar cada parte de tu aplicación utiliza más recursos de memoria y esto puede afectar negativamente al rendimiento de tu aplicación.

Sólo debe utilizar este hook cuando una función ejecutada repetidamente pueda resultar en una mala experiencia para el usuario. Por ejemplo, llamadas a la API caras o lentas. Pero para una función que hace cálculos simples, no hay problema en que se ejecute cada vez.

useCallback vs useMemo

Al igual que el hook useCallback, el hook useMemo se utiliza para memoizar valores en componentes funcionales. La diferencia entre ambos hooks es que useCallback devuelve una función callback memoizada mientras que useMemo devuelve un valor memoizado.

Es decir, al utilizar el hook useMemo, la función callback que se le pasa se ejecuta, y se devuelve un valor memoizado a la variable. Pero con el hook useCallback, la función callback que se le pasa es memoizada y devuelta a la variable.

Aquí tienes un bloque de código para explicarlo:


const var1 = useMemo(() => {
  return 1 + 1
}, [...])

const var2 = useCallback(() => {
  return 1 + 1
}, [...])

console.log(var1)
// 2
console.log(var2)
// () => { return 1 + 1 }

También vale la pena señalar que el useCallback toma una función de devolución de llamada como un argumento que también puede tener argumentos. Por ejemplo:


const var1 = useMemo((número) => {
  return 1 + número
}, [...])

// ...
var1(50)

Esto facilita la reutilización de funciones. Pero no puedes hacer lo mismo con el hook useMemo.

Conclusión

En este artículo, hemos visto qué es el hook useCallback, cómo funciona, un caso de uso para él, cuándo no deberías usarlo y cómo se compara con el hook useMemo.

Para reiterar, este hook se utiliza para memoizar funciones en React, lo que puede ser muy útil para ejecutar dichas funciones cuando lo necesites, y no cuando cambie un estado aleatorio.

Añada afiliaciones a su proyecto Webflow en cuestión de minutos.

Más información

Más de 200 componentes Webflow clonables gratuitos. No es necesario registrarse.

Ver biblioteca

Añade membresías a tu proyecto React en cuestión de minutos.

Empezar
¿Qué es Memberstack?

Autenticación y pagos para sitios Webflow

Añada inicios de sesión, suscripciones, contenido cerrado y mucho más a su sitio Webflow: fácil y totalmente personalizable.

Más información
Empezar a construir

Pruebe Memberstack y descubra todo lo que puede crear.

Memberstack es 100% gratis hasta que estés listo para lanzarla - así que, ¿a qué estás esperando? Crea tu primera aplicación y empieza a construir hoy mismo.