React - Context API
Tags: react, javascript, redux
Published: 2019-01-22 16:31:34

Hasta antes de la versión 16, solo había una forma -nativa- de compartir propiedades entre componentes y era por medio de _Prop drilling_ o, dicho en español, _taladramiento_ ,que quiere decir, que las propiedades fluyen de arriba hacia abajo en una jerarquía previamente establecida.

## Prop Drilling y Redux

Era común tener componentes como el siguiente:

```javascript
class Me extends React.Component<P, S> {
  state = {
    lastName = 'Garzaki'
  }
  render = _ => (
    <div>
      <p>Hola, yo soy Gustavo {this.state.lastName} y mi niña se llama </p>
      <Child lastName={this.state.lastName} />
    </div>
  )
}

class Child extends React.Component<P, S> {
  render = _ => (
    <p>Mía {this.props.lastName}</p>
  )
}
```

A esto se le llama _prop drilling_ que no es más que pasar las propiedades de padre a hijo, de hijo a nieto, de nieto a bisnieto y así sucesivamente. Con el pasar del tiempo llegaron nuevas librerías complementarias para React, como Redux, Mobx, entre otras, que lo que ofrecen es un **manejo de estados intercomponentes**, el cual es global, de manera que no es necesario taladrar toda la jerarquía de componentes para pasar propiedades desde el componente `A` hasta el `F` dentro de la jerarquía, si no que solo necesitas *subscribirte* al estado o a una parte de él para estar **escuchando por cambios** en las propiedades que forman parte de esa porción del estado. Además de esto, nos proveen una manera realmente sencilla de compartir propiedades entre hermanos.

![68747470733a2f2f766963746f72766870672e6769746875622e696f2f6173736574732f636f6e746575646f2d706f7374732f323031382f72656475782f72656475782e706e67](https://camo.githubusercontent.com/777e7ba1d6296e1b17660f11a3d53bf619048a73/68747470733a2f2f766963746f72766870672e6769746875622e696f2f6173736574732f636f6e746575646f2d706f7374732f323031382f72656475782f72656475782e706e67)

Sin embargo, esto trajo consigo una consecuencia inminente e inevitable: **complejidad**. Necesitábamos tener en cuenta los middlewares, las acciones, configurar el store, entre otros, lo que hacía y hace aún a Redux bastante complejo de implementar.

## Context API - ¿Alternativa a Redux? 🤔

A partir de React 16, se implementó una nueva herramienta conocida como [Context API](). Esta nueva herramienta se creó como propuesta al _prop drilling_ y a Redux. La idea detrás de Context API es la misma que Redux, pero de manera mucho más ligera, concisa y lo mejor de todo, oficial.

Esta nueva característica funciona creando un *contexto*, que es un entorno en tiempo de ejecución que guarda ciertos datos, como variables, funciones, entre otras. Este contexto se divide en dos: `Provider` y `Consumer`.

![prop-drilling-v-context.png](https://www.carlrippon.com/wp-content/uploads/2018/04/prop-drilling-v-context.png)

Para crear un contexto, basta con usar el método `React.createContext`:

```javascript
const AppContext = React.createContext({})
export const AppProvider = AppContext.Provider
export const AppConsumer = AppContext.Consumer
```

El **Provider** es donde se almacena la información que se quiere consumir; esta información se pasa por un atributo llamado `value`. Piensa en esto como si fuese una API a la cual vamos a consumir.

Por otro lado, el **Consumer** es el elemento que se encarga de consumir los datos que contiene el **Provider**, de manera que actúa como un _proxy_ para nuestros componentes.

```javascript
import { AppProvider, AppConsumer } from './context'

class App extends Component<P, S> {
  state = {
    title: 'Hello from App',
    updateTitle: title => {
      this.setState({ title })
    }
  }
  render = _ => (
    <AppProvider value={this.state}>
      <Header />
      {this.props.children}
    </AppProvider>
  )
}

export default App
```

Una vez que el `Provider` ya tiene un valor, se puede consumir sin importar la profundidad en donde se encuentre el componente que desea consumir la información:

```javascript
const Header = _ => (
  <header className="header">
    <Title />
  </header>
)
```

```javascript
const Title = _ => (
  <AppConsumer>
  {
    context => (
      <h1 className="header__title">
        { context.title }
      </h1>
    )
  }
)
```

Como vemos, a pesar que el componente `Title` no es hijo directo de `App`, podemos hacer uso de su estado sin heredarlo como propiedad, aún si `Title` estuviese a muchos niveles más de profundidad.

No solo eso, también podemos actualizar el valor del `Provider` actualizando el estado del componente que lo provee. Las posibilidades son muchas y depende de ti como desarrollador decidir el uso que le quieres dar.

---

## Conclusiones

Context API es una alternativa bastante buena a Redux. Si lo que buscas es algo simple y funcional, es la opción para ti. Sin embargo, pueden existir ocasiones en que no sea lo suficientemente útil para ti y quieras usar Redux y otra alternativa. En lo personal, me basta con Context API e incluso para crear mi propio Redux basada en ella como [React Waterfall](https://github.com/didierfranc/react-waterfall).