useContext es un hook de React que proporciona a los componentes funcionales acceso directo a los datos de un contexto creado mediante createContext. El contexto en React resuelve el problema de props drilling — pasar props a través de múltiples componentes intermedios que no utilizan estos datos por sí mismos. Según la React Documentation (2025), useContext recibe un objeto de contexto y devuelve el valor actual establecido por el Provider más cercano en el árbol de componentes. Cuando el valor en el Provider cambia, todos los componentes que usan useContext se vuelven a renderizar automáticamente.
Puntos clave
useContext es un hook añadido en React 16.8 junto con otros hooks que permite leer un valor del contexto de React. El contexto es un mecanismo integrado en React diseñado para pasar datos a través del árbol de componentes sin necesidad de pasar props manualmente en cada nivel. useContext reemplaza el componente Consumer de la antigua Context API y hace que el código sea más conciso y legible.
Los casos de uso típicos del contexto incluyen temas (claro/oscuro), configuración regional y traducciones (i18n), autenticación de usuario, configuraciones de la aplicación y cualquier otro dato global que muchos componentes en diferentes niveles de anidación necesiten. El equipo de React recomienda usar el contexto para datos que son globales para un subárbol de componentes, pero no para toda la aplicación.
Según React Team — Documentación de contexto (2025), el uso incorrecto del contexto es una de las principales causas de problemas de rendimiento en aplicaciones React. Cada cambio de valor en el Provider provoca un re-renderizado de todos los consumidores, independientemente de qué parte de los datos cambió. La optimización mediante useMemo y la división de contextos resuelve este problema.
import { createContext, useContext } from 'react';
// Create context with default value
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={`btn-${theme}`}>Click</button>;
}
El mecanismo de contexto en React se implementa mediante el patrón Provider-Consumer. createContext devuelve un objeto con dos entidades: Provider — un componente que transmite el valor, y el propio objeto de contexto, que se usa en useContext. El Provider se monta en el árbol de componentes y transmite el valor a todos los elementos hijos independientemente de la profundidad de anidación.
Cuando React encuentra una llamada a useContext, recorre el árbol fiber buscando el Provider más cercano para ese contexto. Si se encuentra un Provider, se devuelve su valor. Si no se encuentra ningún Provider, se devuelve el valor predeterminado pasado a createContext. Esta búsqueda ocurre en cada renderizado, pero gracias a la memoización de nodos fiber es muy rápida y no afecta al rendimiento.
Según React — Internos del contexto (2024), la implementación interna de useContext utiliza una lista enlazada de hooks, similar a useState. Cada hook almacena una referencia a un nodo fiber, lo que permite a React determinar rápidamente qué Provider corresponde a ese contexto. Cuando un Provider actualiza su valor, React marca todos los nodos fiber que usan ese contexto para re-renderizado.
Los componentes Provider se pueden anidar unos dentro de otros, creando una jerarquía de contextos. Cada Provider hijo sobrescribe el valor del padre para su propio subárbol. Esto es útil cuando una pantalla necesita un tema claro mientras que una ventana modal anidada necesita un tema oscuro. useContext siempre devuelve el valor del Provider más cercano hacia arriba en el árbol.
const UserContext = createContext(null);
const ThemeContext = createContext('light');
function App() {
return (
<UserContext.Provider value={{ name: 'Alice' }}>
<ThemeContext.Provider value='dark'>
<Profile />
</ThemeContext.Provider>
</UserContext.Provider>
);
}
La función createContext(defaultValue) crea un objeto de contexto. El parámetro defaultValue se usa cuando un componente llama a useContext pero no hay un Provider correspondiente arriba en el árbol. Sin defaultValue, useContext devolverá undefined, lo que puede provocar errores inesperados. Se recomienda pasar siempre un valor predeterminado significativo o null.
Crear un proveedor personalizado es un patrón común para encapsular la lógica del contexto. Dentro de dicho proveedor se almacena el estado (mediante useState o useReducer) y se proporciona a través de la prop value del Provider. Esto oculta los detalles de implementación de los componentes consumidores y centraliza la lógica de gestión del contexto en un solo lugar.
// Custom provider with state management
const AuthContext = createContext(null);
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = useCallback(async (email, pass) => {
const u = await loginApi(email, pass);
setUser(u);
}, []);
return (
<AuthContext.Provider value={{ user, login }}>
{children}
</AuthContext.Provider>
);
}
En los componentes funcionales, useContext es la única forma de acceder al contexto. Reemplaza el componente Consumer de la antigua Context API, que requería el patrón render-prop: <ThemeContext.Consumer>{value => ...}</ThemeContext.Consumer>. useContext hace que el código sea más lineal y legible, especialmente al trabajar con múltiples contextos en un mismo componente.
Al usar múltiples contextos en un componente, simplemente llama a useContext varias veces para cada contexto. Cada llamada devuelve el valor del Provider correspondiente. El orden de las llamadas no importa, ya que cada contexto es una entidad independiente. React optimiza las múltiples llamadas mediante el mismo sistema de referencias fiber.
function Dashboard() {
const { user } = useContext(AuthContext);
const theme = useContext(ThemeContext);
const { locale } = useContext(I18nContext);
return (
<div className={`dashboard-${theme}`}>
<h1>{locale.greeting}, {user.name}</h1>
</div>
);
}
La elección entre useContext y Redux depende de la escala y complejidad de la gestión del estado. useContext + useReducer es un reemplazo ligero de Redux para aplicaciones pequeñas y medianas. No requiere instalar una biblioteca externa, es más fácil de aprender y es suficiente para la mayoría de las tareas. Redux se justifica cuando se requiere una arquitectura estricta con middleware, devtools y actualizaciones inmutables.
La principal ventaja de Redux sobre useContext es la optimización de re-renderizados. Por defecto, cuando el valor en un Provider cambia, todos los consumidores del contexto se re-renderizan. Redux con useSelector y shallowEqual permite que los componentes se suscriban solo a partes específicas del estado, lo que reduce significativamente el número de re-renderizados en aplicaciones grandes. El contexto también se puede optimizar dividiéndolo en muchos contextos pequeños.
| Criterio | useContext | Redux |
|---|---|---|
| Complejidad | Sin dependencias externas | Requiere configuración de store y middleware |
| Re-renderizados | Todos los consumidores ante cualquier cambio | Solo los suscritos a un slice específico |
| DevTools | React DevTools | Redux DevTools con viaje en el tiempo |
| Middleware | No compatible | Redux Thunk, Saga, Observable |
| Cuándo elegir | Aplicaciones medianas, 3–5 contextos | Aplicaciones grandes con lógica de negocio compleja |
Según Mantenedores de Redux — Cuándo usar Redux (2024), el 70% de las aplicaciones React no necesitan Redux. Si tienes menos de 50 componentes y el estado no implica lógica compleja con caché, debounce y efectos secundarios — useContext + useReducer es más que suficiente. Redux añade boilerplate y debe usarse de forma consciente.
El error más común es recrear el objeto value en cada renderizado del Provider. Si pasas value={{ user, login }} al Provider, se crea un nuevo objeto en cada renderizado del Provider, lo que provoca que todos los consumidores se re-rendericen incluso si los datos no han cambiado. La solución es memorizar el valor con useMemo o usar contextos separados para datos que cambian con frecuencia y con poca frecuencia.
// ❌ New object on every render — all consumers re-render
<AuthContext.Provider value={{ user, login }}>{children}</AuthContext.Provider>
// ✅ Memoized value — re-render only when user or login changes
const authValue = useMemo(() => ({ user, login }), [user, login]);
<AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>
Para resolver el problema del “contexto grande”, divide el estado global en grupos lógicos: AuthContext, ThemeContext, I18nContext. Cada contexto es responsable de su propia área y se actualiza de forma independiente. Esto es más simple que intentar optimizar un contexto gigante mediante useMemo, y ofrece un comportamiento de re-renderizado más predecible.
Preguntas frecuentes
Sí, si pasas una función mutadora en el value del Provider. El patrón típico es almacenar el estado en el Provider y pasar tanto los datos como las funciones de actualización a través de useContext. Los componentes hijos llaman a estas funciones, y el cambio de estado en el Provider actualiza automáticamente a todos los consumidores. Es un reemplazo básico de Redux para aplicaciones pequeñas.
Para escenarios simples, useContext es más rápido debido a la ausencia de overhead del store y middleware. Pero con actualizaciones frecuentes y muchos consumidores, Redux gana porque sus selectores (useSelector) se suscriben a partes específicas del estado, mientras que useContext vuelve a renderizar a todos los consumidores ante cualquier cambio. Para aplicaciones con alta frecuencia de actualizaciones (animaciones, tiempo real), elige Redux o bibliotecas especializadas.
No. useContext, como todos los hooks, solo puede llamarse dentro de un componente funcional de React o un hook personalizado. Si necesitas obtener el valor del contexto en una función normal (por ejemplo, en una utilidad o servicio), pásalo como parámetro desde el componente o usa un módulo separado con estado global fuera de React.
La tipificación del contexto en TypeScript se realiza especificando el tipo en createContext: createContext<AuthContextType | null>(null). Esto garantiza que useContext(AuthContext) devuelva un valor del tipo correcto. Un patrón conveniente es crear un hook personalizado useAuth que llame a useContext, verifique si es null y lance un error claro: “useAuth debe usarse dentro de AuthProvider”.
La razón más común es que el componente consumidor no está dentro del Provider correspondiente. Verifica que el Provider envuelva todo el subárbol donde se usa useContext. La segunda razón es que el Provider recibió un objeto de contexto diferente: el desarrollador crea un contexto con createContext pero usa useContext con una instancia diferente de createContext.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también