Primeros pasos con la API de React Hooks

Publicado: 2022-03-10
Resumen rápido ↬ En este tutorial, aprenderá y comprenderá qué son los ganchos de React, los ganchos de React básicos que están disponibles y también ejemplos de cómo escribirlos para sus aplicaciones de React. En el proceso, también conocerá algunos ganchos adicionales que se enviaron con React 16.8 y también cómo escribir sus propios React Hooks personalizados.

Cuando React 16.8 se lanzó oficialmente a principios de febrero de 2019, se envió con una API adicional que le permite usar el estado y otras funciones en React sin escribir una clase. Esta API adicional se llama Hooks y se está volviendo popular en el ecosistema React, desde proyectos de código abierto hasta su uso en aplicaciones de producción.

Los React Hooks son completamente opcionales, lo que significa que no es necesario reescribir el código existente, no contienen cambios importantes y están disponibles para su uso con el lanzamiento de React 16.8. Algunos desarrolladores curiosos han estado haciendo uso de la API de Hooks incluso antes de su lanzamiento oficial, pero en ese entonces no era estable y solo era una característica experimental. Ahora es estable y se recomienda que lo usen los desarrolladores de React.

Nota : No hablaremos de React o JavaScript en general. Un buen conocimiento de ReactJS y JavaScript será útil mientras trabaja en este tutorial.

¿Qué son los ganchos de reacción?

Los React Hooks son funciones integradas que permiten a los desarrolladores de React usar métodos de estado y ciclo de vida dentro de componentes funcionales, también funcionan junto con el código existente, por lo que pueden adoptarse fácilmente en una base de código. La forma en que los Hooks se lanzaron al público fue que permitían a los desarrolladores usar el estado en componentes funcionales, pero bajo el capó, los Hooks son mucho más poderosos que eso. Permiten a los desarrolladores de React disfrutar de los siguientes beneficios:

  • Reutilización de código mejorada;
  • Mejor composición de código;
  • Mejores valores predeterminados;
  • Compartir lógica no visual con el uso de ganchos personalizados;
  • Flexibilidad para moverse hacia arriba y hacia abajo en el árbol de components .

Con React Hooks, los desarrolladores obtienen el poder de usar componentes funcionales para casi todo lo que necesitan hacer, desde solo renderizar la interfaz de usuario hasta manejar el estado y la lógica, lo cual es bastante bueno.

Motivación detrás del lanzamiento de React Hooks

De acuerdo con la documentación oficial de ReactJS, las siguientes son las motivaciones detrás del lanzamiento de React Hooks:

  • La reutilización de la lógica con estado entre los componentes es difícil.
    Con Hooks, puede reutilizar la lógica entre sus componentes sin cambiar su arquitectura o estructura.
  • Los componentes complejos pueden ser difíciles de entender.
    Cuando los componentes se vuelven más grandes y realizan muchas operaciones, se vuelve difícil de entender a largo plazo. Los ganchos resuelven esto al permitirle separar un componente único en particular en varias funciones más pequeñas en función de qué partes de este componente separado están relacionadas (como configurar una suscripción o obtener datos), en lugar de tener que forzar una división según los métodos del ciclo de vida.
  • Las clases son bastante confusas.
    Las clases son un obstáculo para aprender Reaccionar correctamente; necesitaría comprender cómo funciona this en JavaScript, que difiere de otros idiomas. React Hooks resuelve este problema al permitir que los desarrolladores usen lo mejor de las funciones de React sin tener que usar clases.
¡Más después del salto! Continúe leyendo a continuación ↓

Las reglas de los anzuelos

Hay dos reglas principales que deben cumplirse estrictamente según lo establecido por el equipo central de React en las que se describen en la documentación de la propuesta de ganchos.

  • Asegúrate de no usar Hooks dentro de bucles, condiciones o funciones anidadas;
  • Solo use Hooks desde dentro de React Functions.

Ganchos de reacción básicos

Hay 10 ganchos incorporados que se enviaron con React 16.8, pero los ganchos básicos (de uso común) incluyen:

  • useState()
  • useEffect()
  • useContext()
  • useReducer()

Estos son los 4 ganchos básicos que comúnmente usan los desarrolladores de React que han adoptado React Hooks en sus bases de código.

useState()

El gancho useState() permite a los desarrolladores de React actualizar, manejar y manipular el estado dentro de los componentes funcionales sin necesidad de convertirlo en un componente de clase. Usemos el fragmento de código a continuación que es un componente de contador de edad simple y lo usaremos para explicar el poder y la sintaxis del gancho useState() .

 function App() { const [age, setAge] = useState(19); const handleClick = () => setAge(age + 1) return <div> I am {age} Years Old <div> <button onClick={handleClick}>Increase my age! </button> </div> </div> }

Si lo ha notado, nuestro componente parece bastante simple, conciso y ahora es un componente funcional y tampoco tiene el nivel de complejidad que tendría un componente de clase.

El gancho useState() recibe un estado inicial como argumento y luego regresa, haciendo uso de la desestructuración de arreglos en JavaScript, las dos variables en el arreglo pueden llamarse what. La primera variable es el estado real, mientras que la segunda variable es una función destinada a actualizar el estado proporcionando un nuevo estado.

Nuestra aplicación React terminada (vista previa grande)

Así es como debería verse nuestro componente cuando se renderiza en nuestra aplicación React. Al hacer clic en el botón "Aumentar mi edad", el estado de la edad cambiará y el componente funcionará como un componente de clase con estado.

useEffect()

El gancho useEffect() acepta una función que contendría código efectivo. En los componentes funcionales, no se permite colocar efectos como mutaciones, suscripciones, temporizadores, registros y otros efectos dentro de un componente funcional porque hacerlo generaría muchas inconsistencias cuando se representa la interfaz de usuario y también errores confusos.

Al usar el gancho useEffect() , la función eficaz que se le pasa se ejecutará justo después de que el renderizado se haya mostrado en la pantalla. Los efectos básicamente se asomaron a la forma imperativa de construir interfaces de usuario que es bastante diferente de la forma funcional de React.

De forma predeterminada, los efectos se ejecutan principalmente después de que se haya completado el renderizado, pero tiene la opción de activarlos también cuando cambian ciertos valores.

El gancho useEffect() se utiliza principalmente para los efectos secundarios que generalmente se usan para las interacciones con la API del navegador/DOM ​​o la obtención de datos o suscripciones externas similares a las API. Además, si ya está familiarizado con el funcionamiento de los métodos del ciclo de vida de React, también puede pensar en el gancho useEffect() como el montaje , actualización y desmontaje de componentes, todo combinado en una función. Nos permite replicar los métodos del ciclo de vida en componentes funcionales.

Usaremos los fragmentos de código a continuación para explicar la forma más básica en que podemos usar el gancho useEffect() .

Paso 1: Defina el estado de su aplicación

 import React, {useState} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Tal como discutimos en la sección anterior sobre cómo usar el gancho useState() para manejar el estado dentro de los componentes funcionales, lo usamos en nuestro fragmento de código para establecer el estado de nuestra aplicación que representa mi nombre completo.

Paso 2: llama al gancho useEffect

 import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({FirstName: 'Shedrack', surname: 'Akintayo'}) }, [])//pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Ahora hemos importado el gancho useEffect y también hemos hecho uso de la función useEffect() para establecer el estado de nuestra propiedad de nombre y apellido, que es bastante clara y concisa.

Es posible que haya notado el useEffect en el segundo argumento, que es una matriz vacía; esto se debe a que contiene una llamada a setFullName que no tiene una lista de dependencias. Pasar el segundo argumento evitará una cadena infinita de actualizaciones ( componentDidUpdate() ) y también permitirá que nuestro useEffect() actúe como un método de ciclo de vida de componentDidMount y se renderice una vez sin volver a renderizar en cada cambio en el árbol.

Nuestra aplicación React ahora debería verse así:

Aplicación React usando useEffect Hook (vista previa grande)

También podemos cambiar la propiedad del title de nuestra aplicación dentro de la función useEffect() llamando a la función setTitle() , así:

 import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({firstName: 'Shedrack', surname: 'Akintayo'}) setTitle({'My Full Name'}) //Set Title }, [])// pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Ahora, después de que nuestra aplicación se haya vuelto a renderizar, ahora muestra el nuevo título.

Nuestro proyecto terminado (vista previa grande)

useContext()

El gancho useContext() acepta un objeto de contexto, es decir, el valor que se devuelve desde React.createContext , y luego devuelve el valor de contexto actual para ese contexto.

Este enlace brinda a los componentes funcionales un fácil acceso al contexto de su aplicación React. Antes de que se introdujera el useContext , necesitaría configurar un contextType o un <Consumer> para acceder a su estado global transmitido por algún proveedor en un componente de clase.

Básicamente, el useContext funciona con la API React Context, que es una forma de compartir datos profundamente en toda su aplicación sin la necesidad de pasar manualmente los accesorios de su aplicación a través de varios niveles. Ahora, useContext() hace que usar Context sea un poco más fácil.

Los fragmentos de código que aparecen a continuación mostrarán cómo funciona la API de contexto y cómo el gancho useContext la mejora.

La forma normal de usar la API de contexto

 import React from "react"; import ReactDOM from "react-dom"; const NumberContext = React.createContext(); function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); } function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

Desglosemos ahora el fragmento de código y expliquemos cada concepto.

A continuación, estamos creando un contexto llamado NumberContext . Está destinado a devolver un objeto con dos valores: { Provider, Consumer } .

 const NumberContext = React.createContext();

Luego usamos el valor del Provider que se devolvió del NumberContext que creamos para hacer que un valor particular esté disponible para todos los niños.

 function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); }

Con eso, podemos usar el valor del Consumer que se devolvió del NumberContext que creamos para obtener el valor que pusimos a disposición de todos los niños. Si te has dado cuenta, este componente no recibió ningún apoyo.

 function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

Observe cómo pudimos obtener el valor del componente de la App en el componente de Display envolviendo nuestro contenido en un NumberContext.Consumer y usando el método de render props para recuperar el valor y renderizarlo.

Todo funciona bien y el método de render props que usamos es un patrón realmente bueno para manejar datos dinámicos, pero a la larga, introduce un anidamiento y confusión innecesarios si no está acostumbrado.

Usando el método useContext

Para explicar el método useContext , reescribiremos el componente Display usando el gancho useContext.

 // import useContext (or we could write React.useContext) import React, { useContext } from 'react'; // old code goes here function Display() { const value = useContext(NumberContext); return <div>The answer is {value}.</div>; }

Eso es todo lo que necesitamos hacer para mostrar nuestro valor. Bastante ordenado, ¿verdad? Llama al gancho useContext() y pasa el objeto de contexto que creamos y tomamos el valor de él.

Nota: No olvide que el argumento que se pasa al enlace useContext debe ser el objeto de contexto en sí mismo y cualquier componente que llame a useContext siempre se volverá a representar cuando cambie el valor del contexto.

useReducer()

El gancho useReducer se usa para manejar estados complejos y transiciones en el estado. Admite una función reducer y también una entrada de estado inicial; luego, devuelve el estado actual y también una función de dispatch como salida por medio de la desestructuración de la matriz.

El siguiente código es la sintaxis adecuada para usar el gancho useReducer .

 const [state, dispatch] = useReducer(reducer, initialArg, init);

Es una especie de alternativa al hook useState ; por lo general, es preferible useState cuando tiene una lógica de estado compleja que tiene que ver con múltiples subvalores o cuando el siguiente estado depende del anterior.

Otros ganchos de reacción disponibles

useCallback Este enlace devuelve una función de devolución de llamada que se memoriza y que solo cambia si cambia una dependencia en el árbol de dependencia.
useMemo Este enlace devuelve un valor memorizado, puede pasar una función de "crear" y también una matriz de dependencias. El valor que devuelve solo usará el valor memorizado nuevamente si cambia una de las dependencias en el árbol de dependencia.
useRef Este enlace devuelve un objeto ref mutable cuya propiedad .current se inicializa en el argumento pasado ( initialValue ). El objeto devuelto estará disponible durante toda la vida útil del componente.
useImperativeHandle Este gancho se usa para personalizar el valor de la instancia que está disponible para los componentes principales cuando se usan referencias en React.
useLayoutEffect Este gancho es similar al gancho useEffect , sin embargo, se dispara sincrónicamente después de todas las mutaciones DOM. También se representa de la misma manera que componentDidUpdate y componentDidMount .
useDebugValue Este gancho se puede usar para mostrar una etiqueta para ganchos personalizados en React Dev Tools. Es muy útil para depurar con React Dev Tools.

Ganchos de reacción personalizados

Un "Hook personalizado" es una función de JavaScript cuyos nombres tienen el prefijo use y se puede usar para llamar a otros Hooks. También le permite extraer la lógica de los componentes en funciones reutilizables; son funciones normales de JavaScript que pueden hacer uso de otros Hooks dentro de él, y también contienen una lógica de estado común que se puede utilizar dentro de múltiples componentes.

Los fragmentos de código a continuación muestran un ejemplo de un React Hook personalizado para implementar el desplazamiento infinito (por Paulo Levy):

 import { useState } from "react"; export const useInfiniteScroll = (start = 30, pace = 10) => { const [limit, setLimit] = useState(start); window.onscroll = () => { if ( window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight ) { setLimit(limit + pace); } }; return limit; };

Este Hook personalizado acepta dos argumentos que son start y pace . El argumento de inicio es el número inicial de elementos que se van a representar, mientras que el argumento de ritmo es el número subsiguiente de elementos que se van a representar. De forma predeterminada, los argumentos de start y pace se establecen en 30 y 10 respectivamente, lo que significa que en realidad puede llamar al gancho sin ningún argumento y, en su lugar, se utilizarán esos valores predeterminados.

Entonces, para usar este Hook dentro de una aplicación React, lo usaríamos con una API en línea que devuelve datos 'falsos':

 import React, { useState, useEffect } from "react"; import { useInfiniteScroll } from "./useInfiniteScroll"; const App = () => { let infiniteScroll = useInfiniteScroll(); const [tableContent, setTableContent] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/") .then(response => response.json()) .then(json => setTableContent(json)); }, []); return ( <div style={{ textAlign: "center" }}> <table> <thead> <tr> <th>User ID</th> <th>Title</th> </tr> </thead> <tbody> {tableContent.slice(0, infiniteScroll).map(content => { return ( <tr key={content.id}> <td style={{ paddingTop: "10px" }}>{content.userId}</td> <td style={{ paddingTop: "10px" }}>{content.title}</td> </tr> ); })} </tbody> </table> </div> ); }; export default App;

El código anterior generará una lista de datos falsos ( userID de usuario y title ) que utilizan el gancho de desplazamiento infinito para mostrar el número inicial de datos en la pantalla.

Conclusión

Espero que hayas disfrutado trabajando en este tutorial. Siempre puede leer más sobre React Hooks en las referencias a continuación.

Si tienes alguna pregunta, puedes dejarla en la sección de comentarios y estaré encantado de responder a cada una de ellas.

El repositorio de apoyo para este artículo está disponible en Github.

Recursos y lecturas adicionales

  • "Referencia de la API de ganchos", React.js Docs
  • "¿Qué son los ganchos de reacción?", Robin Wieruch
  • “Cómo funciona el gancho useContext ”, Dave Ceddia
  • “React Hooks: Cómo usar useEffect() ”, Hossein Ahmadi, Medium
  • "Escribir sus propios ganchos de reacción personalizados", Aayush Jaiswal, mediano
  • "Recetas fáciles de entender de React Hook", Gabe Ragland, useHooks()