Desmitificando los Hooks de React — useCallback

Empezando
Si desea seguirlo en su IDE local, puede encontrar el GitHub Repo aquí .
clone
cd client
npm i
npm start
La igualdad referencial es un concepto fundamental tanto en JavaScript como en informática en su conjunto. Entonces, comencemos con una demostración en acción.
He incorporado capturas de pantalla a lo largo del artículo para facilitar su uso en dispositivos móviles. Si está en el escritorio y lo ha clonado, ejecute referentialEquality.js
para observar el resultado o simplemente juegue con el fragmento JSFiddle incrustado a continuación.
Al evaluar si el integer 1
es estrictamente igual al integer 1
, la consola imprime true
. Esto se debe a que, bueno... el integer 1
es estrictamente igual al integer 1
.

Vemos el mismo resultado cuando evaluamos dos cadenas.

Obviamente, este siempre será el caso para dos tipos de datos primitivos del mismo valor.
Ahora, ¿qué pasa con las estructuras de datos? Por ejemplo, ¿dos objetos literales con los mismos pares clave/valor? ¿Qué pasa con los literales de objetos vacíos?

¿Por qué esta impresión false
? Al comparar si estos dos objetos literales son estrictamente iguales, JavaScript usa sus respectivas direcciones de memoria .
En otras palabras, estos dos objetos pueden contener los mismos valores , pero no hacen referencia al mismo objeto . Se ven iguales pero ocupan dos espacios diferentes en la memoria .
¡Lo mismo se aplica si está comparando dos literales de objeto, dos literales de matriz o dos funciones!

Para demostrar esto aún más, definiremos una función func
, que devuelve una función anónima que, a su vez, devuelve algo más ( como un elemento JSX ).

Entonces asignaremos dos funciones diferentes, firstRender
y secondRender
, igual al valor devuelto por func
.

Piense en func
su componente funcional React, mientras que firstRender
es una función dentro de él en el primer renderizado, y secondRender
es una función dentro de él en el segundo renderizado.
Aunque firstRender
y secondRender
devuelven el mismo valor y se asignan desde la misma definición, no tienen igualdad referencial . Como resultado, cada vez que el componente se renderiza, redefine esta función.

Desafortunadamente, en JavaScript, no es fácil imprimir estas direcciones de memoria como en Python, pero para obtener una explicación un poco más detallada de la referencia frente al valor, consulte este artículo de freeCodeCamp.
Este tema puede volverse denso y no es necesario que dé una clase sobre el tema esta noche. Entonces, por ahora, solo recuerda:
- tipo de datos primitivo
===
tipo de datos primitivo - estructura de datos
!==
estructura de datos.
Código de inicio
Después de activar nuestra aplicación, abra el BookDetails.jsx
componente y vuelva a guardar. Lo primero que podemos notar en nuestro servidor de desarrollo React es algo común WARNING
que los desarrolladores jóvenes tienden a ignorar. A medida que ingrese a la fuerza laboral y comience a escribir código para producción, sus linters serán aún más estrictos que lo que está integrado en create-react-app
. WARNINGS
se dirigirá a ERRORS
, y algunos linters no le permitirán presionar antes de abordar estos ERRORS
.
Entonces, en lugar de ignorarlo, averigüemos cómo tratarlo.

NOTA: es posible que primero deba volver a guardar BookDetails.jsx
para crear esteWARNING
Si profundizamos en React Docs , podemos decodificar las soluciones propuestas semiconfusas a esto WARNING
de la siguiente manera:
1. Incluya la definición de la función dentro del archivo useEffect
.
- No podemos llamar a esta función en otro lugar a menos que la redefinamos.
- Esto activará
useEffect
cada vez que cambie el estado o los accesorios, lo que a veces provocará una repetición infinita. Y en nuestro caso, dado que estamos llamando a nuestra función de establecimiento de estado después de una llamada a la API, podría sobrecargar nuestra API con infinitas solicitudes de puntos finales.
- La función no será llamada.
- La primera vez que el componente se renderiza, definirá nuestra función, lo que activará el
useEffect
, lo que hará que el componente se vuelva a renderizar, lo que redefinirá la función, lo que activará eluseEffect
, lo que hará que el componente se vuelva a renderizar, lo que redefinirá la función…
La solución más simple y preferida sería 'incluirla', es decir, mover la getBookDetails
definición de la función dentro del archivo useEffect
. Esto se adhiere a un principio de Programación Orientada a Objetos conocido como Encapsulación .
Pero digamos que sabemos que necesitamos llamar a la función en otro lugar. ¿Deberíamos redefinirlo más tarde? Eso no es muy SECO de nuestra parte.
Cambiemos nuestra matriz de dependencias para incluir nuestra referencia de función. Tu useEffect
ahora debería verse así.

Y getBookDetails
permanece definido por encima del useEffect
.

Ahora tenemos un nuevoWARNING

Ingrese el gancho useCallback
En resumen, el useCallback
enlace le permite almacenar en caché, o 'memorizar', una función entre renderizaciones de su componente. Realiza una tarea similar a useMemo
, cuyos matices abordaremos en un artículo diferente.
Si le interesa el meollo de la cuestión, puede leer más en los documentos de React .
Tenga en cuenta su advertencia:
Solo debe confiar en useCallback
una optimización del rendimiento. Si su código no funciona sin él, encuentre el problema subyacente y arréglelo primero. Luego puede agregar useCallback
para mejorar el rendimiento.
useCallback
Sintaxis
useCallback
La sintaxis de es muy similar a la useEffect
sintaxis de que ya conocemos. Mira los esqueletos de cada uno.

La pequeña diferencia es que con useEffect
, le decimos a la función anónima que ejecute nuestra función, mientras que con useCallback
, asignamos el valor devuelto a una referencia para llamar en otro lugar.
Usando useCallback
Primero, importaremos useCallback
desde 'react'
. En lugar de agregar una nueva línea, es mejor desestructurarla junto con nuestras otras importaciones.

Ahora podemos asignar getBookDetails
al valor devuelto por una useCallback
llamada de función.

Luego agregamos toda la sintaxis para useCallback
. ¡Recuerda tu matriz de dependencia!

En nuestro ejemplo, necesitamos async
antes de nuestros parámetros.

Y finalmente, agregamos la lógica de nuestra función al bloque de código.

Una vez que guardamos, obtenemos... otro WARNING
.

¿ Por qué nuestra matriz de dependencias debe rastrear la id
variable?
Pensemos en esto.
- Si el valor de
id
cambia,getBookDetails
necesita llegar a un punto final diferente, entonces React debería redefinirlo. La definición degetBookDetails
literalmente depende del valor deid
.

Y finalmente, ¡eso es todo! Vemos verde en nuestro servidor de desarrollo React. Un linter feliz es un desarrollador senior feliz. ¡Y un desarrollador sénior feliz es un tú feliz!
Siempre estoy buscando nuevos amigos y colegas. Si este artículo le resultó útil y desea conectarse, puede encontrarme en cualquiera de mis casas en la web.
GitHub | Gorjeo | LinkedIn | Sitio web
Recursos
- Igualdad Referencial
- Tipos de datos primitivos de JavaScript frente a estructuras de datos
- Encapsulación
useCallback
- Reaccionar documentos