paint-brush
Cómo simplificar la gestión del estado con la API de contexto React.js: un tutorialpor@codebucks
Nueva Historia

Cómo simplificar la gestión del estado con la API de contexto React.js: un tutorial

por CodeBucks11m2024/08/02
Read on Terminal Reader

Demasiado Largo; Para Leer

Este blog ofrece una guía completa sobre cómo administrar el estado en React usando la API Context. Explica cómo evitar la perforación de puntales, mejorar el rendimiento e implementar la API Context de manera efectiva. Con ejemplos prácticos y consejos de optimización, es perfecto para los desarrolladores que buscan optimizar la gestión del estado en sus aplicaciones React.
featured image - Cómo simplificar la gestión del estado con la API de contexto React.js: un tutorial
CodeBucks HackerNoon profile picture
0-item

Hola👋🏻,


Este artículo está creado específicamente para principiantes que desean aprender métodos más efectivos para administrar el estado entre múltiples componentes. También tiene como objetivo abordar el problema común de la perforación de puntales, que puede hacer que su código sea más difícil de mantener y comprender. Comencemos con qué tipo de problema resuelve la API de contexto.


Si prefieres el formato de vídeo, aquí tienes el tutorial que puedes ver en mi canal de YouTube.👇🏻


¿Qué es la perforación de puntal?

¿Sabes que a veces necesitas pasar datos de un componente principal a un componente secundario y terminas pasando accesorios a través de un montón de componentes intermedios? Eso se llama perforación de puntal y puede resultar complicado rápidamente. Veamos un ejemplo para aclarar esto.


Perforación de accesorios en React.js

Como se muestra en el diagrama, imagine que ha obtenido algunos datos en el componente App , que se encuentra en la raíz de su aplicación. Ahora, si un componente profundamente anidado, digamos el componente Grandchild , necesita acceder a estos datos, normalmente los transmitirá a través de los componentes Parent e Child como accesorios antes de que llegue Grandchild . Esto puede volverse feo a medida que su aplicación crece.


Aquí hay otra representación visual:


Ejemplo de perforación de accesorios de Reactjs

En el ejemplo anterior, el componente Profile necesita datos del usuario, pero estos datos deben viajar primero a través de los componentes App y Navigation , aunque estos componentes intermedios no usan los datos por sí mismos. Entonces, ¿cómo limpiamos esto? Ahí es donde la API Context resulta útil.


Perforación de puntales:

  • Aumenta la reproducción de componentes.
  • Aumenta el código repetitivo
  • Crea dependencia de componentes.
  • Disminuye el rendimiento

Reaccionar API de contexto

La API de contexto en React.js le permite pasar datos entre componentes sin necesidad de pasarlos como accesorios a través de cada nivel del árbol de componentes. Funciona como un sistema de gestión de estado global en el que usted define su estado en un objeto de contexto y luego puede acceder fácilmente a él en cualquier parte del árbol de componentes. Entendamos esto con un ejemplo.


API de contexto React.js

Como puede ver en el diagrama, tenemos un objeto de contexto que almacena datos a los que pueden acceder varios componentes. Estos datos se obtienen de API o servicios de terceros. Antes de acceder a estos datos de contexto en cualquier componente, debemos empaquetar todos los componentes que requieren estos datos en un componente de proveedor de contexto.


Si solo necesitamos acceder a los datos en los componentes de navegación y perfil, no necesitamos finalizar el componente de la aplicación. Una vez que haya empaquetado los componentes relevantes con ContextProvider , puede acceder directamente a los datos de contexto en cualquier componente que los consuma. No te preocupes si aún no lo entiendes; Profundicemos en el código y veámoslo en acción.


¿Cómo utilizar la API de contexto?

Primero, creemos una aplicación React usando Vite.js. Simplemente copie los siguientes comandos para configurar el proyecto.


 npm create vite@latest


  • Añade el nombre de tu proyecto
  • Seleccione Reaccionar
  • Seleccione texto mecanografiado de las opciones
 cd project_name // to change to project directory npm install npm run dev


Luego puede abrir su servidor de desarrollo http://localhost:5173 en su navegador.


Primero, creemos las carpetas necesarias. Aquí está la estructura de carpetas de nuestro proyecto.

 src | components | context


En la carpeta de componentes, creemos el archivo Profile.jsx y agreguemos el siguiente código.

 import React from 'react' const Profile = () => { return ( <div>Profile</div> ) } export default Profile


Cree un componente más llamado Navbar.jsx en la carpeta de componentes.

 import Profile from './Profile' const Navbar = () => { return ( <nav style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "90%", height: "10vh", backgroundColor: theme === "light" ? "#fff" : "#1b1b1b", color: theme === "light" ? "#1b1b1b" : "#fff", border: "1px solid #fff", borderRadius: "5px", padding: "0 20px", marginTop: "40px", }}> <h1>LOGO</h1> <Profile /> </nav> ) } export default Navbar


Importemos este componente <Navbar /> en el archivo App.jsx .

 import Navbar from "./components/Navbar"; function App() { return ( <main style={{ display: "flex", flexDirection: "column", justifyContent: "start", alignItems: "center", height: "100vh", width: "100vw", }} > <Navbar /> </main> ); } export default App;


Básicamente, el componente <Profile /> es hijo de <Navbar /> y <Navbar /> es hijo del componente <App /> .

Agregar API de contexto

Creemos el archivo UserContext.jsx en la carpeta context . Agregue el siguiente código al archivo.


 import { createContext, useEffect, useState } from "react"; export const UserContext = createContext(); export const UserProvider = ({ children }) => { const [user, setUser] = useState(null); const fetchUserData = async (id) => { const response = await fetch( `https://jsonplaceholder.typicode.com/users/${id}` ).then((response) => response.json()); console.log(response); setUser(response); }; useEffect(() => { fetchUserData(1); }, []); return ( <UserContext.Provider value={{ user, fetchUserData }} > {children} </UserContext.Provider> ); };


  • Primero, creamos un objeto UserContext vacío usando createContext . Nos aseguramos de importarlo desde react . Podemos agregar valores predeterminados dentro del objeto de contexto, pero lo mantenemos nulo por ahora.


  • A continuación, creamos UserProvider , que devuelve un proveedor usando UserContext , como UserContext.Provider . Envuelve los componentes secundarios y, en el valor, podemos pasar cualquier cosa que queramos usar en los componentes secundarios.


  • En este momento, estamos utilizando la API jsonplaceholder para recuperar los datos del usuario. El jsonplaceholder proporciona puntos finales API falsos con fines de prueba. La función fetchUserData acepta id y la utiliza para recuperar los datos del usuario. Luego almacenamos la respuesta en el estado user .


  • Estamos llamando a la función fetchUserData en useEffect por lo que al cargar la página, llama a la función e inyecta los datos en el estado user .


Ahora, usemos este contexto en el componente <App /> . Envuelva el componente <NavBar /> usando <UserProvider /> ; Lo mismo que el siguiente código:

 <UserProvider> <Navbar /> </UserProvider>


Usemos el estado user en el componente <Profile /> . Para eso, usaremos el gancho useContext . Eso toma UserContext y proporciona los valores que hemos pasado en UserProvider , como el estado user y la función fetchUserData . Recuerde, no necesitamos empaquetar el componente <Profile /> ya que ya está en el componente <Navbar /> que ya está empaquetado con el proveedor.


Abra Profile.jsx y agregue el siguiente código.

 const { user } = useContext(UserContext); if (user) { return ( <span style={{ fontWeight: "bold", }} > {user.name} </span> ); } else { return <span>Login</span>; }


Aquí, estamos usando el estado user del UserContext . Mostraremos el nombre de usuario si hay user ; de lo contrario, mostraremos solo un mensaje de inicio de sesión. Ahora, si ve el resultado, debería haber un nombre de usuario en el componente de la barra de navegación. Así es como podemos usar directamente cualquier estado que esté en el contexto de cualquier componente. El componente que utiliza este estado debe incluirse dentro de <Provider /> .


También puede utilizar múltiples contextos. Solo necesita envolver los componentes del proveedor dentro de otro componente del proveedor como se muestra en el siguiente ejemplo.

 <ThemeProvider> <UserProvider> <Navbar /> </UserProvider> </ThemeProvider>


En el ejemplo anterior, utilizamos <ThemeProvider /> que gestiona el estado del tema.


Puede ver el vídeo de YouTube anterior para ver el ejemplo completo del uso de múltiples proveedores de contexto.

Optimización del renderizado en la API de contexto de React

Hay un problema que ocurre cuando usa la API Context en múltiples componentes. Siempre que el estado o el valor cambia en la API de contexto, vuelve a representar todos los componentes suscritos a ese contexto en particular, incluso si no todos los componentes están utilizando el estado modificado. Para comprender este problema de reproducción, creemos un componente <Counter /> que utilice el contexto para almacenar y mostrar valores de recuento.


Mira el siguiente ejemplo. Puede crear un archivo Counter.jsx en la carpeta de componentes y pegar el siguiente código.


 import { createContext, memo, useContext, useState } from "react"; const CountContext = createContext(); const CountProvider = ({ children }) => { const [count, setCount] = useState(0); return ( <CountContext.Provider value={{ count, setCount }}> {children} </CountContext.Provider> ); }; function CountTitle() { console.log("This is Count Title component"); return <h1>Counter Title</h1>; } function CountDisplay() { console.log("This is CountDisplay component"); const { count } = useContext(CountContext); return <div>Count: {count}</div>; } function CounterButton() { console.log("This is CounterButton component"); const { count, setCount } = useContext(CountContext); return ( <> <CountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </> ); } export default function Counter() { return ( <CountProvider> <CounterButton /> </CountProvider> ); }


En el código anterior:

  • Primero, creamos un objeto CountContext usando createContext.


  • En CountProvider, tenemos un estado para almacenar valores de recuento. Estamos enviando count y el método setCount a los componentes secundarios a través de value prop.


  • Hemos creado componentes por separado para ver cuántas veces se vuelven a renderizar los componentes individuales.

    • <CountTitle /> : este componente muestra solo el título y ni siquiera utiliza ningún valor del contexto.

    • <CountDisplay /> : este componente muestra valores de recuento y utiliza el estado count del contexto.

    • <CounterButton /> : este componente representa tanto el componente anterior como un botón que aumenta los valores de recuento usando setCount .


  • Al final, envolvemos el componente <CounterButton /> dentro del componente CountProvider para que los otros componentes puedan acceder a los valores de recuento.


Ahora, si ejecuta el código y hace clic en el botón Increase , verá en los registros que cada componente se vuelve a representar cada vez que cambia el estado. <CountTitle /> ni siquiera utiliza valores de recuento, pero se está volviendo a representar. Esto sucede porque el componente principal de <CountTitle /> que es <CounterButton /> está usando y actualizando el valor de recuento y es por eso que se vuelve a representar.


¿Cómo podemos optimizar este comportamiento? La respuesta es memo . La memo de React le permite omitir volver a renderizar un componente cuando sus accesorios no han cambiado. Después del componente <CountTitle /> , agreguemos la siguiente línea.


 const MemoizedCountTitle = React.memo(CountTitle)


Ahora, en el componente <CounterButton /> , donde estamos representando el componente <CountTitle /> , reemplace <CountTitle /> con <MemoizedCountTitle /> como en el siguiente código:


 <> <MemoizedCountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </>


Ahora, si aumenta el recuento y verifica los registros, debería poder ver que ya no representa el componente <CountTitle /> .

Redux frente a API de contexto

Redux es una biblioteca de gestión de estados para una gestión de estados compleja con transiciones de estado más predecibles. Mientras que la API Context está diseñada para una gestión de estado sencilla y para pasar datos a través del árbol de componentes sin necesidad de profundizar. Entonces, ¿cuándo elegir cuál?


  • Utilice la API React Context para una gestión de estado localizada y sencilla donde el estado no cambia con frecuencia.


  • Utilice Redux para necesidades complejas de administración de estado, especialmente en aplicaciones más grandes donde los beneficios de su administración de estado estructurada superan la configuración adicional.


También hay otra biblioteca que también es una opción popular para la gestión estatal. El retroceso de reacción .


  • React Recoil es una biblioteca de gestión de estado para React que tiene como objetivo proporcionar la simplicidad de Context API con la potencia y el rendimiento de Redux.


Si está interesado en aprender más sobre React Recoil , hágamelo saber en los comentarios y crearé tutoriales detallados sobre este tema en función de sus comentarios.

Conclusión

La API de contexto React.js ofrece una forma poderosa y eficiente de administrar estados en múltiples componentes, abordando de manera efectiva el problema de la perforación de puntales. Al utilizar la API Context, puede simplificar su código, reducir las reproducciones innecesarias y mejorar el rendimiento general de la aplicación.


Si bien la API Context es ideal para una administración de estado simple, las aplicaciones más complejas pueden beneficiarse del uso de Redux u otras bibliotecas de administración de estado como React Recoil . Comprender cuándo y cómo utilizar estas herramientas le permitirá crear aplicaciones React más escalables y fáciles de mantener.


Gracias por leer este artículo, espero que te haya resultado útil. Si está interesado en aprender y crear proyectos usando React, Redux y Next.js, puede visitar mi canal de YouTube aquí: CodeBucks


Aquí están mis otros artículos que quizás le guste leer:

Visita mi blog personal: DevDreaming