Desmitificando los Hooks de React — useCallback

Dec 03 2022
En este artículo, exploraremos cuándo y cómo usar el enlace useCallback de React y un error cometido por la mayoría de los desarrolladores junior.
Primeros pasos Si desea realizar un seguimiento en su IDE local, puede encontrar el GitHub Repo aquí. La igualdad referencial es un concepto fundamental tanto en JavaScript como en informática en su conjunto.

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.jspara observar el resultado o simplemente juegue con el fragmento JSFiddle incrustado a continuación.

Al evaluar si el integer 1es estrictamente igual al integer 1, la consola imprime true. Esto se debe a que, bueno... el integer 1 es estrictamente igual al integer 1.

los enteros son estrictamente iguales

Vemos el mismo resultado cuando evaluamos dos cadenas.

las cuerdas son estrictamente iguales

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?

los objetos no son estrictamente iguales

¿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!

las matrices no son estrictamente iguales

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 ).

crear un componente funcional simulado

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

asignando nuestras definiciones de funciones

Piense en funcsu componente funcional React, mientras que firstRenderes una función dentro de él en el primer renderizado, y secondRenderes una función dentro de él en el segundo renderizado.

Aunque firstRendery secondRenderdevuelven 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.

nuestras dos funciones no son estrictamente iguales

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.jsxcomponente y vuelva a guardar. Lo primero que podemos notar en nuestro servidor de desarrollo React es algo común WARNINGque 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. WARNINGSse 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.

Soluciones propuestas por React

NOTA: es posible que primero deba volver a guardar BookDetails.jsxpara crear esteWARNING

Si profundizamos en React Docs , podemos decodificar las soluciones propuestas semiconfusas a esto WARNINGde 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á el useEffect, 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 getBookDetailsdefinició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 useEffectahora debería verse así.

incluyendo nuestra función en la matriz de dependencia

Y getBookDetailspermanece definido por encima del useEffect.

la definición original de nuestra función

Ahora tenemos un nuevoWARNING

definir nuestra función fuera de useEffect mientras la incluimos en la matriz de dependencia provocará una repetición infinita

Ingrese el gancho useCallback

En resumen, el useCallbackenlace 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 useCallbackuna optimización del rendimiento. Si su código no funciona sin él, encuentre el problema subyacente y arréglelo primero. Luego puede agregar useCallbackpara mejorar el rendimiento.

useCallbackSintaxis

useCallbackLa sintaxis de es muy similar a la useEffectsintaxis de que ya conocemos. Mira los esqueletos de cada uno.

los dos ganchos tienen esqueletos sintácticos idénticos

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 useCallbackdesde 'react'. En lugar de agregar una nueva línea, es mejor desestructurarla junto con nuestras otras importaciones.

los artículos desestructurados del mismo paquete se importan mejor en la misma línea

Ahora podemos asignar getBookDetailsal valor devuelto por una useCallbackllamada de función.

asignar el retorno de useCallback a nuestra referencia

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

complete el esqueleto de useCallback

En nuestro ejemplo, necesitamos asyncantes de nuestros parámetros.

agregar asíncrono

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

agregue nuestra lógica al bloque de código de useCallback

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

el retorno de useCallback depende del valor de id

¿ Por qué nuestra matriz de dependencias debe rastrear la idvariable?

Pensemos en esto.

  • Si el valor de idcambia, getBookDetailsnecesita llegar a un punto final diferente, entonces React debería redefinirlo. La definición de getBookDetailsliteralmente depende del valor de id.
versiones terminadas de ambos ganchos

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