Hooks de React útiles que puedes utilizar en tus proyectos

 

 

 

  • SmashingConf Nueva York 2024
  • Planificación y proceso del sistema de diseño, con Nathan Curtis

  • Índice
    1. Motivación detrás de los ganchos #
      1. Infierno de envoltura #
      2. Componentes enormes #
      3. Clases confusas #
    2. La convención y las reglas de Hooks #
    3. El useStategancho #
      1. Componentes de renderizado #
      2. Establecer estados conuseState #
      3. Configuración de matrices y estados de objetos #
      4. Naturaleza asíncrona deuseState #
    4. El useEffectgancho #
      1. Limpiando el efecto #
      2. Obteniendo y recuperando datos conuseEffect #
    5. El useReducergancho #
      1. Usando useContexty useReducer#

    Los componentes basados ​​en clases de React son confusos, confusos y difíciles para los humanos y las máquinas. Pero antes de React 16.8, los componentes basados ​​en clases eran obligatorios para cualquier proyecto que requiriera estados, métodos de ciclo de vida y muchas otras funcionalidades importantes. Todo esto cambió con la introducción de ganchos en React 16.8. Los ganchos cambian las reglas del juego. Han simplificado React, lo han hecho más claro, más fácil de escribir y depurar, y también han reducido la curva de aprendizaje.

     

    Los ganchos son simplemente funciones que le permiten conectarse o utilizar las funciones de React. Se presentaron en React Conf 2018 para abordar tres problemas principales de los componentes de clase: infierno de envoltorios, componentes enormes y clases confusas. Los ganchos dan poder a los componentes funcionales de React, haciendo posible desarrollar una aplicación completa con ellos.

    Los problemas antes mencionados de los componentes de clase están conectados y resolver uno sin el otro podría introducir más problemas. Afortunadamente, los ganchos resolvieron todos los problemas de manera simple y eficiente y al mismo tiempo crearon espacio para funciones más interesantes en React. Los ganchos no reemplazan los conceptos y clases de React ya existentes, simplemente proporcionan una API para acceder a ellos directamente.

    El equipo de React introdujo varios ganchos en React 16.8. Sin embargo, también puede utilizar enlaces de proveedores externos en su aplicación o incluso crear un enlace personalizado. En este tutorial, veremos algunos ganchos útiles en React y cómo usarlos. Revisaremos varios ejemplos de código de cada gancho y también exploraremos cómo crear un gancho personalizado.

    Nota: Este tutorial requiere conocimientos básicos de Javascript (ES6+) y React.

    Motivación detrás de los ganchos #

    Como se indicó anteriormente, los ganchos se crearon para resolver tres problemas: infierno de envoltorios, componentes enormes y clases confusas. Echemos un vistazo a cada uno de estos con más detalle.

    Infierno de envoltura #

    Las aplicaciones complejas creadas con componentes de clase se ejecutan fácilmente en el infierno de los contenedores. Si examina la aplicación en React Dev Tools, notará componentes profundamente anidados. Esto hace que sea muy difícil trabajar con los componentes o depurarlos. Si bien estos problemas podrían resolverse con componentes de orden superior y accesorios de renderizado , requieren que modifiques un poco tu código. Esto podría generar confusión en una aplicación compleja.

    Los ganchos son fáciles de compartir, no es necesario modificar los componentes antes de reutilizar la lógica.

    Un buen ejemplo de esto es el uso del connectcomponente de orden superior (HOC) de Redux para suscribirse a la tienda Redux. Como todos los HOC, para utilizar Connect HOC, debe exportar el componente junto con las funciones de orden superior definidas. En el caso de connect, tendremos algo de esta forma.

    export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)

    Donde mapStateToPropsy mapDispatchToPropsson funciones por definir.

    Mientras que en la era de los Hooks, se puede lograr fácilmente el mismo resultado de forma clara y concisa utilizando Redux useSelectory useDispatchHooks.

    Componentes enormes #

    Los componentes de clase suelen contener efectos secundarios y lógica con estado. A medida que la aplicación crece en complejidad, es común que el componente se vuelva confuso y confuso. Esto se debe a que se espera que los efectos secundarios estén organizados por métodos de ciclo de vida en lugar de por funcionalidad. Si bien es posible dividir los componentes y hacerlos más simples, esto a menudo introduce un mayor nivel de abstracción.

     

    Los ganchos organizan los efectos secundarios por funcionalidad y es posible dividir un componente en partes según la funcionalidad.

    Clases confusas #

    Las clases son generalmente un concepto más difícil que las funciones. Los componentes basados ​​en clases de React son detallados y un poco difíciles para los principiantes. Si es nuevo en Javascript, es posible que le resulte más fácil comenzar con las funciones debido a su sintaxis liviana en comparación con las clases. La sintaxis puede resultar confusa; A veces, es posible olvidar vincular un controlador de eventos, lo que podría romper el código.

    React resuelve este problema con componentes funcionales y ganchos, lo que permite a los desarrolladores centrarse en el proyecto en lugar de en la sintaxis del código.

    Por ejemplo, los siguientes dos componentes de React producirán exactamente el mismo resultado.

    import React, { Component } from "react";export default class App extends Component { constructor(props) { super(props); this.state = { num: 0 }; this.incrementNumber = this.incrementNumber.bind(this); } incrementNumber() { this.setState({ num: this.state.num + 1 }); } render() { return ( div h1{this.state.num}/h1 button onClick={this.incrementNumber}Increment/button /div ); }}
    import React, { useState } from "react";export default function App() { const [num, setNum] = useState(0); function incrementNumber() { setNum(num + 1); } return ( div h1{num}/h1 button onClick={incrementNumber}Increment/button /div );}

    El primer ejemplo es un componente basado en clases, mientras que el segundo es un componente funcional. Aunque este es un ejemplo simple, observe cuán falso es el primer ejemplo comparado con el segundo.

    La convención y las reglas de Hooks #

    Antes de profundizar en los distintos ganchos, podría resultar útil echar un vistazo a las convenciones y reglas que se les aplican. Estas son algunas de las reglas que se aplican a los anzuelos.

    1. La convención de nomenclatura de ganchos debe comenzar con el prefijo use. Entonces, podemos tener useState,, useEffectetc. Si está utilizando editores de código modernos como Atom y VSCode, el complemento ESLint podría ser una característica muy útil para los ganchos de React. El complemento proporciona advertencias útiles y sugerencias sobre las mejores prácticas.
    2. Los ganchos deben llamarse en el nivel superior de un componente, antes de la declaración de devolución. No se pueden llamar dentro de una declaración condicional, un bucle o funciones anidadas.
    3. Los ganchos deben llamarse desde una función de React (dentro de un componente de React u otro gancho). No debería llamarse desde una función Vanilla JS.

    El useStategancho #

    El useStategancho es el gancho de React más básico y útil. Al igual que otros ganchos integrados, este gancho debe importarse reactpara usarlo en nuestra aplicación.

     

    import {useState} from 'react'

    Para inicializar el estado, debemos declarar tanto el estado como su función de actualización y pasar un valor inicial.

    const [state, updaterFn] = useState('')

    Somos libres de llamar a nuestro estado y función de actualización como queramos, pero por convención, el primer elemento de la matriz será nuestro estado mientras que el segundo elemento será la función de actualización. Es una práctica común anteponer a nuestra función de actualización el conjunto de prefijos seguido del nombre de nuestro estado en formato camello.

    Por ejemplo, establezcamos un estado para mantener los valores de recuento.

    const [count, setCount] = useState(0)

    Observe que el valor inicial de nuestro countestado se establece en 0y no en una cadena vacía. En otras palabras, podemos inicializar nuestro estado con cualquier tipo de variable de JavaScript, es decir, número, cadena, booleano, matriz, objeto e incluso BigInt. Existe una clara diferencia entre establecer estados con el useStategancho y los estados de componentes basados ​​en clases. Cabe destacar que el useStategancho devuelve una matriz, también conocida como variables de estado y, en el ejemplo anterior, desestructuramos la matriz en statey la updaterfunción.

    Componentes de renderizado #

    Establecer estados con el useStategancho hace que el componente correspondiente se vuelva a representar. Sin embargo, esto solo sucede si React detecta una diferencia entre el estado anterior o antiguo y el nuevo estado. React realiza la comparación de estados utilizando el Object.is algoritmo Javascript .

    Establecer estados conuseState #

    Nuestro countestado se puede establecer en nuevos valores de estado simplemente pasando el nuevo valor a la setCountfunción de actualización de la siguiente manera setCount(newValue).

    Este método funciona cuando no queremos hacer referencia al valor del estado anterior. Si deseamos hacer eso, debemos pasar una función a la setCountfunción.

    Suponiendo que queremos agregar 5 a nuestra countvariable cada vez que se hace clic en un botón, podríamos hacer lo siguiente.

    import {useState} from 'react'const CountExample = () = { // initialize our count state const [count, setCount] = useState(0) // add 5 to to the count previous state const handleClick = () ={ setCount(prevCount = prevCount + 5) } return( div h1{count} /h1 button onClick={handleClick}Add Five/button /div )}export default CountExample

    En el código anterior, primero importamos el useStategancho reacty luego inicializamos el countestado con un valor predeterminado de 0. Creamos un onClickcontrolador para incrementar el valor de counten 5 cada vez que se hace clic en el botón. Luego mostramos el resultado en una h1etiqueta.

    Configuración de matrices y estados de objetos #

    Los estados de matrices y objetos se pueden configurar de la misma manera que otros tipos de datos. Sin embargo, si deseamos conservar los valores ya existentes, debemos utilizar el operador de extensión ES6 al configurar los estados.

     

    El operador de extensión en Javascript se utiliza para crear un nuevo objeto a partir de un objeto ya existente. Esto es útil aquí porque Reactcompara los estados con la Object.isoperación y luego vuelve a renderizar en consecuencia.

    Consideremos el siguiente código para configurar estados al hacer clic en un botón.

    import {useState} from 'react'const StateExample = () = { //initialize our array and object states const [arr, setArr] = useState([2, 4]) const [obj, setObj] = useState({num: 1, name: 'Desmond'}) // set arr to the new array values const handleArrClick = () ={ const newArr = [1, 5, 7] setArr([...arr, ...newArr]) } // set obj to the new object values const handleObjClick = () ={ const newObj = {name: 'Ifeanyi', age: 25} setObj({...obj, ...newObj}) } return( div button onClick ={handleArrClick}Set Array State/button button onClick ={handleObjClick}Set Object State/button /div )}export default StateExample

    En el código anterior, creamos dos estados arry objlos inicializamos en algunos valores de matriz y objeto respectivamente. Luego creamos onClickcontroladores llamados handleArrClicky handleObjClickpara establecer los estados de la matriz y el objeto respectivamente. Cuando handleArrClickse activa, llamamos setArry usamos el operador de extensión de ES6 para distribuir los valores de la matriz ya existentes y agregarlos newArr.

    Hicimos lo mismo con handleObjClickel controlador. Aquí llamamos setObj, difundimos los valores de los objetos existentes utilizando el operador de extensión ES6 y actualizamos los valores de namey age.

    Naturaleza asíncrona deuseState #

    Como ya hemos visto, configuramos estados useStatepasando un nuevo valor a la función de actualización. Si se llama al actualizador varias veces, los nuevos valores se agregarán a una cola y se volverá a representar en consecuencia mediante la Object.iscomparación de JavaScript.

    Los estados se actualizan de forma asincrónica. Esto significa que el nuevo estado se agrega primero a un estado pendiente y luego se actualiza el estado. Por lo tanto, aún puede obtener el valor del estado anterior si accede al estado inmediatamente establecido.

    Consideremos el siguiente ejemplo para observar este comportamiento.

    En el código anterior, creamos un countestado usando el useStategancho. Luego creamos un onClickcontrolador para incrementar el countestado cada vez que se hace clic en el botón. Observe que aunque el countestado aumentó, como se muestra en la h2etiqueta, el estado anterior todavía está registrado en la consola. Esto se debe a la naturaleza asíncrona del gancho. Blog de Nutricion, Entrenamiento y Fitness

    Si deseamos obtener el nuevo estado, podemos manejarlo de manera similar a como manejaríamos las funciones asíncronas. Aquí hay una manera de hacerlo.

    Aquí, almacenamos creado newCountValuepara almacenar el valor de recuento actualizado y luego configuramos el countestado con el valor actualizado. Luego, registramos el valor del recuento actualizado en la consola.

     

    • Leverage robust data-fetching and optimized bundle size with the KendoReact Server Data Grid Try now

    El useEffectgancho #

    useEffectes otro gancho de React importante utilizado en la mayoría de los proyectos. Hace algo similar a los métodos de ciclo de vida componentDidMount, componentWillUnmounty del componente basado en clases componentDidUpdate. useEffectNos brinda la oportunidad de escribir códigos imperativos que pueden tener efectos secundarios en la aplicación. Ejemplos de tales efectos incluyen registros, suscripciones, mutaciones, etc.

    El usuario puede decidir cuándo se useEffectejecutará; sin embargo, si no está configurado, los efectos secundarios se ejecutarán en cada renderizado o rerenderizado.

    Considere el siguiente ejemplo.

    import {useState, useEffect} from 'react'const App = () ={ const [count, setCount] = useState(0) useEffect(() ={ console.log(count) }) return( div ... /div )}

    En el código anterior, simplemente iniciamos sesión counten el archivo useEffect. Esto se ejecutará después de cada renderizado del componente.

    A veces, es posible que queramos ejecutar el gancho una vez (en el soporte) en nuestro componente. Podemos lograr esto proporcionando un segundo parámetro para useEffectenganchar.

    import {useState, useEffect} from 'react'const App = () ={ const [count, setCount] = useState(0) useEffect(() ={ setCount(count + 1) }, []) return( div h1{count}/h1 ... /div )}

    El useEffectgancho tiene dos parámetros, el primer parámetro es la función que queremos ejecutar mientras que el segundo parámetro es una serie de dependencias. Si no se proporciona el segundo parámetro, el enlace se ejecutará continuamente.

    Al pasar un corchete vacío al segundo parámetro del gancho, le indicamos a React que ejecute el useEffectgancho solo una vez, en el soporte. Esto mostrará el valor 1en la h1etiqueta porque el recuento se actualizará una vez, de 0 a 1, cuando se monte el componente.

    También podríamos hacer que nuestro efecto secundario se ejecute cada vez que cambien algunos valores dependientes. Esto se puede hacer pasando estos valores en la lista de dependencias.

    Por ejemplo, podríamos hacer que useEffectse ejecute cada vez que countcambie de la siguiente manera.

    import { useState, useEffect } from "react";const App = () = { const [count, setCount] = useState(0); useEffect(() = { console.log(count); }, [count]); return ( div button onClick={() = setCount(count + 1)}Increment/button /div );};export default App;

    Lo useEffectanterior se ejecutará cuando se cumpla cualquiera de estas dos condiciones.

    1. Al montar: después de renderizar el componente.
    2. Cuando el valor de countcambia.

    Al montar, la console.logexpresión se ejecutará y registrará counten 0. Una vez que se countactualiza, se cumple la segunda condición, por lo que se useEffectejecuta nuevamente, esto continuará cada vez que se haga clic en el botón.

     

    Una vez que proporcionamos el segundo argumento a useEffect, se espera que le pasemos todas las dependencias. Si lo ha ESLINTinstalado, mostrará un error de pelusa si no se pasa alguna dependencia a la lista de parámetros. Esto también podría hacer que el efecto secundario se comporte de forma inesperada, especialmente si depende de los parámetros que no se pasan.

    Limpiando el efecto #

    useEffectTambién nos permite limpiar recursos antes de que el componente se desmonte. Esto puede ser necesario para evitar pérdidas de memoria y hacer que la aplicación sea más eficiente. Para hacer esto, devolveríamos la función de limpieza al final del gancho.

    useEffect(() = { console.log('mounted') return () = console.log('unmounting... clean up here')})

    El useEffectgancho de arriba registrará mountedcuando se monte el componente. Desmontando... la limpieza aquí se registrará cuando el componente se desmonte. Esto puede suceder cuando el componente se elimina de la interfaz de usuario.

    El proceso de limpieza suele seguir el siguiente formulario.

    useEffect(() = { //The effect we intend to make effect //We then return the clean up return () = the cleanup/unsubscription})

    Si bien es posible que no encuentre tantos casos de uso para useEffectlas suscripciones, resulta útil cuando se trata de suscripciones y temporizadores. En particular, cuando se trata de sockets web, es posible que deba cancelar la suscripción a la red para ahorrar recursos y mejorar el rendimiento cuando se desmonta el componente.

    Obteniendo y recuperando datos conuseEffect #

    Uno de los casos de uso más comunes del useEffectgancho es obtener y precargar datos de una API.

    Para ilustrar esto, usaremos datos de usuario falsos que creé JSONPlaceholderpara recuperar datos con el useEffectgancho.

    import { useEffect, useState } from "react";import axios from "axios";export default function App() { const [users, setUsers] = useState([]); const endPoint = "https://my-json-server.typicode.com/ifeanyidike/jsondata/users"; useEffect(() = { const fetchUsers = async () = { const { data } = await axios.get(endPoint); setUsers(data); }; fetchUsers(); }, []); return ( div className="App" {users.map((user) = ( div h2{user.name}/h2 pOccupation: {user.job}/p pSex: {user.sex}/p /div ))} /div );}

    In the code above, we created a users state using the useState hook. Then we fetched data from an API using Axios. This is an asynchronous process, and so we used the async/await function, we could have also used the dot then the syntax. Since we fetched a list of users, we simply mapped through it to display the data.

    Notice that we passed an empty parameter to the hook. This ensures that it is called just once when the component mounts.

     

    We can also refetch the data when some conditions change. We’ll show this in the code below.

    import { useEffect, useState } from "react";import axios from "axios";export default function App() { const [userIDs, setUserIDs] = useState([]); const [user, setUser] = useState({}); const [currentID, setCurrentID] = useState(1); const endPoint = "https://my-json-server.typicode.com/ifeanyidike/userdata/users"; useEffect(() = { axios.get(endPoint).then(({ data }) = setUserIDs(data)); }, []); useEffect(() = { const fetchUserIDs = async () = { const { data } = await axios.get(`${endPoint}/${currentID}`}); setUser(data); }; fetchUserIDs(); }, [currentID]); const moveToNextUser = () = { setCurrentID((prevId) = (prevId userIDs.length ? prevId + 1 : prevId)); }; const moveToPrevUser = () = { setCurrentID((prevId) = (prevId === 1 ? prevId : prevId - 1)); }; return ( div className="App" div h2{user.name}/h2 pOccupation: {user.job}/p pSex: {user.sex}/p /div button onClick={moveToPrevUser}Prev/button button onClick={moveToNextUser}Next/button /div );}

    Here we created two useEffect hooks. In the first one, we used the dot then syntax to get all users from our API. This is necessary to determine the number of users.

    We then created another useEffect hook to get a user based on the id. This useEffect will refetch the data whenever the id changes. To ensure this, we passed the id in the dependency list.

    Next, we created functions to update the value of our id whenever the buttons are clicked. Once the value of the id changes, the useEffect will run again and refetch the data.

    If we want, we can even clean up or cancel the promise-based token in Axios, we could do that with the clean-up method discussed above.

    useEffect(() = { const source = axios.CancelToken.source(); const fetchUsers = async () = { const { data } = await axios.get(`${endPoint}/${num}`, { cancelToken: source.token }); setUser(data); }; fetchUsers(); return () = source.cancel(); }, [num]);

    Here, we passed the Axios’ token as a second parameter to axios.get. When the component unmounts we then canceled the subscription by calling the cancel method of the source object.

    El useReducergancho #

    The useReducer hook is a very useful React hook that does a similar thing to the useState hook. According to the React documentation, this hook should be used to handle more complex logic than the useState hook. It’s worthy of note that the useState hook is internally implemented with the useReducer hook.

    The hook takes a reducer as an argument and can optionally take the initial state and an init function as arguments.

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

    Here, init is a function and it is used whenever we want to create the initial state lazily.

    Let’s look at how to implement the useReducer hook by creating a simple to-do app as shown in the sandbox below.

    The React Context API provides a way to share states or data throughout the React component tree. The API has been available in React, as an experimental feature, for a while but it became safe to use in React 16.3.0. The API makes data sharing between components easy while eliminating prop drilling.

     

    While you can apply the React Context to your entire application, it is also possible to apply it to part of the application.

    To use the hook, you need to first create a context using React.createContext and this context can then be passed to the hook.

    To demonstrate the use of the useContext hook, let’s create a simple app that will increase font size throughout our application.

    Let’s create our context in context.js file.

    import { createContext } from "react";//Here, we set the initial fontSize as 16.const fontSizeContext = createContext(16);export default fontSizeContext;

    Here, we created a context and passed an initial value of 16 to it, and then exported the context. Next, let’s connect our context to our application.

    import FontSizeContext from "./context";import { useState } from "react";import PageOne from "./PageOne";import PageTwo from "./PageTwo";const App = () = { const [size, setSize] = useState(16); return ( FontSizeContext.Provider value={size} PageOne / PageTwo / button onClick={() = setSize(size + 5)}Increase font/button button onClick={() = setSize((prevSize) = Math.min(11, prevSize - 5)) } Decrease font /button /FontSizeContext.Provider );};export default App;

    In the above code, we wrapped our entire component tree with FontSizeContext.Provider and passed size to its value prop. Here, size is a state-created with the useState hook. This allows us to change the value prop whenever the size state changes. By wrapping the entire component with the Provider, we can access the context anywhere in our application.

    For instance, we accessed the context in PageOne / and PageTwo /. As a result of this, the font size will increase across these two components when we increase it from the App.js file. We can increase or decrease the font size from the buttons as shown above and once we do, the font size changes throughout the application.

    import { useContext } from "react";import context from "./context";const PageOne = () = { const size = useContext(context); return p style={{ fontSize: `${size}px` }}Content from the first page/p;};export default PageOne;

    Here, we accessed the context using the useContext hook from our PageOne component. We then used this context to set our font-size property. A similar procedure applies to the PageTwo.js file.

    Themes or other higher-order app-level configurations are good candidates for contexts.

    Usando useContexty useReducer#

    When used with the useReducer hook, useContext allows us to create our own state management system. We can create global states and easily manage them in our application.

    Let’s improve our to-do application using the context API.

    As usual, we need to create a todoContext in the todoContext.js file.

    import { createContext } from "react";const initialState = [];export default createContext(initialState);

    Here we created the context, passing an initial value of an empty array. Then we exported the context.

    Let’s refactor our App.js file by separating the to-do list and items.

    import { useReducer, useState } from "react";import "./styles.css";import todoReducer, { ADD_TODO } from "./todoReducer";import TodoContext from "./todoContext";import TodoList from "./TodoList";export default function App() { const [id, setId] = useState(0); const [text, setText] = useState(""); const initialState = []; const [todoState, todoDispatch] = useReducer(todoReducer, initialState); const addTodoItem = (e) = { e.preventDefault(); const newId = id + 1; setId(newId); todoDispatch({ type: ADD_TODO, id: newId, text: text }); setText(""); }; return ( TodoContext.Provider value={[todoState, todoDispatch]} div className="app" h1Todo Example/h1 form className="input" onSubmit={addTodoItem} input value={text} onChange={(e) = setText(e.target.value)} / button disabled={text.length === 0} type="submit" + /button /form TodoList / /div /TodoContext.Provider );}

    Here, we wrapped our App.js file with the TodoContext.Provider then we passed the return values of our todoReducer to it. This makes the reducer’s state and dispatch function to be accessible throughout our application.

    We then separated the to-do display into a component TodoList. We did this without prop drilling, thanks to the Context API. Let’s take a look at the TodoList.js file.

    import React, { useContext } from "react";import TodoContext from "./todoContext";import Todo from "./Todo" 




    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Hooks de React útiles que puedes utilizar en tus proyectos

    Hooks de React útiles que puedes utilizar en tus proyectos

    SmashingConf Nueva York 2024 Planificación y proceso del sistema de diseño, con Nathan Curtis Índice Mo

    programar

    es

    https://aprendeprogramando.es/static/images/programar-hooks-de-react-utiles-que-puedes-utilizar-en-tus-proyectos-1127-0.jpg

    2024-04-04

     

    Hooks de React útiles que puedes utilizar en tus proyectos
    Hooks de React útiles que puedes utilizar en tus proyectos

     

     

    Top 20