# React Context API
Semestre 01, 2026



## Propdrilling


Imaginemos una aplicación con esta estructura:

```
App
├── Header
│   └── UserAvatar
├── Sidebar
│   └── UserSettings
└── MainContent
    └── Dashboard
        └── WelcomeMessage
```

Todos necesitan saber quién está autenticado


### "Solución"

La solución inmediata es pasar `user` como prop a cada componente

```jsx
function App() {
  const user = { name: "María", role: "admin" };

  return (
    <>
      <Header user={user} />
      <Sidebar user={user} />
      <MainContent user={user} />
    </>
  );
}
```

No es escalable


### Ejemplo

```jsx
function MainContent({ user }) {
  return <Dashboard user={user} />;
}

function Dashboard({ user }) {
  return <WelcomeMessage user={user} />;
}

function WelcomeMessage({ user }) {
  return <h1>Hola, {user.name}!</h1>;
}
```

`MainContent` y `Dashboard` no usan `user`

Solo lo pasan hacia abajo — son intermediarios innecesarios


### Definición

Pasar datos a través de componentes que no los necesitan


* Los datos viajan por 3, 4, 5 niveles de componentes intermedios
* Los componentes intermedios quedan "contaminados" con props que no les corresponden


* Si cambia la estructura del árbol, hay que actualizar cada nivel (frágil)
* Es difícil saber quién realmente usa el dato y quién solo lo pasa de largo



## React Context


Context permite que un componente padre proporcione datos a cualquier componente del árbol debajo de él

Sin pasar props manualmente en cada nivel

```
App  ←── provee el valor
├── Header
│   └── UserAvatar  ←── recibe el valor directamente
├── Sidebar
│   └── UserSettings  ←── recibe el valor directamente
└── MainContent
    └── Dashboard
        └── WelcomeMessage  ←── recibe el valor directamente
```


### CSS

Context funciona como la herencia de CSS

* En CSS: se define `color: blue` en el padre, todos los hijos lo heredan
* Con Context: se define un valor en el padre, todos los hijos pueden leerlo

React es explícito sobre qué contexto consumir



## 3 pasos


### Paso 1 — Crear el contexto

```jsx
// UserContext.js
import { createContext } from 'react';

export const UserContext = createContext(null);
```

* `createContext` vive fuera de cualquier componente
* El argumento es el valor por defecto (se usa si no hay Provider arriba)
* Convención: exportar el contexto para usarlo en otros archivos


### Paso 2 — Proveer el contexto

```jsx
// App.jsx
import { UserContext } from './UserContext';

function App() {
  const user = { name: "María", role: "admin" };

  return (
    <UserContext.Provider value={user}>
      <Header />
      <Sidebar />
      <MainContent />
    </UserContext.Provider>
  );
}
```

* `Provider` envuelve los componentes que necesitan el valor
* El prop `value` contiene el dato que se comparte
* Todos los componentes dentro del `Provider` pueden leer `user`


### Paso 3 — Consumir el contexto

```jsx
// WelcomeMessage.jsx
import { useContext } from 'react';
import { UserContext } from './UserContext';

function WelcomeMessage() {
  const user = useContext(UserContext);

  return <h1>Hola, {user.name}!</h1>;
}
```

* `useContext` lee el valor del contexto más cercano en el árbol
* No necesita recibir nada por props
* `MainContent` y `Dashboard` ya no tocan `user`


### Buena práctica

En lugar de importar `UserContext` + `useContext` en cada componente, se encapsula en un hook:


```jsx
// UserContext.js
import { createContext, useContext } from 'react';

export const UserContext = createContext(null);

export function useUser() {
  return useContext(UserContext);
}
```

```jsx
// WelcomeMessage.jsx
import { useUser } from './UserContext';

function WelcomeMessage() {
  const user = useUser();  // un solo import, una sola línea
  return <h1>Hola, {user.name}!</h1>;
}
```

Si cambia la implementación del contexto, solo se actualiza un lugar



## Ejemplo


### Crear el contexto

```jsx
// ThemeContext.js
import { createContext } from 'react';

export const ThemeContext = createContext('light');
```


### Proveer el contexto

```jsx
// App.jsx
import { useState } from 'react';
import { ThemeContext } from './ThemeContext';

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={theme}>
      <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
        Cambiar tema
      </button>
      <Navbar />
      <Main />
    </ThemeContext.Provider>
  );
}
```

Cuando `theme` cambia, todos los consumidores se actualizan automáticamente


### Consumir el contexto

```jsx
// Navbar.jsx
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function Navbar() {
  const theme = useContext(ThemeContext);

  return (
    <nav className={`navbar navbar--${theme}`}>
      Mi Aplicación
    </nav>
  );
}
```


```jsx
// Button.jsx
function Button({ children }) {
  const theme = useContext(ThemeContext);

  return (
    <button className={`btn btn--${theme}`}>
      {children}
    </button>
  );
}
```


### El resultado

Antes — prop drilling:
```
App → Navbar (pasa theme) → NavLinks (pasa theme) → Button ← usa theme
```

Después — Context:
```
App (provee theme)
           ↓
     Button ← lee theme directamente
```

`Navbar` y `NavLinks` ya no necesitan saber que `theme` existe



## Concurrencia


### Un componente puede hacer ambas cosas

Un componente puede leer el contexto del padre y proveer uno nuevo a sus hijos


```jsx
import { useContext } from 'react';
import { LevelContext } from './LevelContext';

function Section({ children }) {
  const level = useContext(LevelContext);  // Lee del padre

  return (
    <LevelContext.Provider value={level + 1}>  // Provee +1 a sus hijos
      <section>{children}</section>
    </LevelContext.Provider>
  );
}
```

Útil para contextos que se acumulan o transforman en cada nivel



## Múltiples contextos


### Pueden coexistir

```jsx
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <UserContext.Provider value={currentUser}>
        <Page />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}
```


```jsx
function Button() {
  const theme = useContext(ThemeContext);
  const user = useContext(UserContext);

  return (
    <button className={theme}>
      Hola, {user.name}
    </button>
  );
}
```

Cada contexto es independiente — no se interfieren entre sí



## Cuándo usar Context


### Casos de uso típicos

| Caso | Qué se comparte |
|------|----------------|
| Tema visual | `'light'` / `'dark'` |
| Usuario autenticado | `{ name, role, token }` |
| Idioma / locale | `'es'` / `'en'` |
| Carrito de compras | `[items]` |
| Estado global simple | Reducer + Context |


Si muchos componentes en distintos niveles necesitan el mismo dato, Context es la herramienta correcta


### Cuándo NO usar Context

* Si son 1 o 2 niveles, las props siguen siendo la mejor opción
