context.api
React.js
Cuando trabajamos con React, compartir datos entre múltiples componentes puede volverse complicado. Inicialmente, usamos useState
para manejar estados locales, pero a medida que nuestra aplicación crece, nos encontramos con problemas como:
Paso de props excesivo: Pasar datos de un componente padre a un componente muy lejano en la jerarquía puede ser frustrante y poco eficiente.
Estados dispersos: Cada componente maneja su propio estado, lo que hace difícil coordinar los cambios globales.
Falta de una gestión centralizada del estado: Sin una estructura adecuada, actualizar el estado de manera global puede volverse desordenado.
React nos proporciona la Context API
para compartir datos sin necesidad de pasar props manualmente, y useReducer
nos ayuda a manejar los cambios de estado de manera predecible y estructurada.
Un estado global que puede ser accedido desde cualquier parte de la aplicación sin necesidad de props.
Un mecanismo centralizado para modificar el estado mediante acciones bien definidas.
Código más organizado y fácil de mantener.
El concepto es simple: un único proveedor comparte información con múltiples consumidores, y useReducer
se encarga de gestionar los cambios de manera estructurada.
Cada vez que el estado cambia, los componentes que lo consumen se actualizan automáticamente. Es similar a una señal de televisión: un canal transmite la señal y todos los televisores que están sintonizados la reciben.
Todo el mundo tiene acceso al contexto global ahora.
Un reducer es una función que recibe el estado actual y una acción, y devuelve un nuevo estado en base a esa acción.
1// store.js - Definimos el estado inicial y las funciones del reducer 2 3export const initialStore = () => ({ 4 todos: ["Hacer la cama", "Sacar la basura"] 5}); 6 7export default function storeReducer(state, action) { 8 switch (action.type) { 9 case "ADD_TODO": 10 return { ...state, todos: [...state.todos, action.payload] }; 11 default: 12 return state; 13 } 14}
Aquí creamos un Contexto y un Provider que envolverá nuestra aplicación para compartir el estado global.
1import { useContext, useReducer, createContext } from "react"; 2import storeReducer, { initialStore } from "../store"; 3 4const StoreContext = createContext(); 5 6export function StoreProvider({ children }) { 7 const [store, dispatch] = useReducer(storeReducer, initialStore()); 8 return ( 9 <StoreContext.Provider value={{ store, dispatch }}> 10 {children} 11 </StoreContext.Provider> 12 ); 13} 14 15export default function useGlobalReducer() { 16 return useContext(StoreContext); 17}
Para que todos los componentes puedan acceder al estado global, debemos envolver nuestra aplicación con el StoreProvider en el archivo principal.
1import React from "react"; 2import ReactDOM from "react-dom"; 3import { StoreProvider } from "./context/StoreContext"; 4import App from "./App"; 5 6ReactDOM.render( 7 <StoreProvider> 8 <App /> 9 </StoreProvider>, 10 document.getElementById("root") 11);
Ahora podemos acceder al estado global y modificarlo desde cualquier componente con useGlobalReducer().
1import React from "react"; 2import useGlobalReducer from "../context/StoreContext"; 3 4const TodoList = () => { 5 const { store, dispatch } = useGlobalReducer(); 6 7 return ( 8 <div> 9 <ul> 10 {store.todos.map((task, i) => ( 11 <li key={i}>{task}</li> 12 ))} 13 </ul> 14 <button onClick={() => dispatch({ type: "ADD_TODO", payload: `Tarea ${store.todos.length + 1}` })}> 15 + Añadir tarea 16 </button> 17 </div> 18 ); 19}; 20 21export default TodoList;
El store es el punto central de nuestra aplicación, por lo que debemos asegurarnos de que su información no se modifique directamente. En su lugar, usamos el dispatch para ejecutar acciones que actualicen el estado.