A tu propio ritmo

Explora nuestra extensa colección de cursos diseñados para ayudarte a dominar varios temas y habilidades. Ya seas un principiante o un aprendiz avanzado, aquí hay algo para todos.

Bootcamp

Aprende en vivo

Únete a nosotros en nuestros talleres gratuitos, webinars y otros eventos para aprender más sobre nuestros programas y comenzar tu camino para convertirte en desarrollador.

Próximos eventos en vivo

Catálogo de contenidos

Para los geeks autodidactas, este es nuestro extenso catálogo de contenido con todos los materiales y tutoriales que hemos desarrollado hasta el día de hoy.

Tiene sentido comenzar a aprender leyendo y viendo videos sobre los fundamentos y cómo funcionan las cosas.

Buscar en lecciones


IngresarEmpezar
← Regresar a lecciones
Editar en Github

Implementando un estado global con context API

Por qué la vida antes de la API de contexto era más difícil

Por qué la vida antes de la API de contexto era más difícil

La gente dice que React.js hace que las cosas fáciles sean difíciles y que las difíciles sean fáciles. Me encanta ese dicho, es tan cierto 😓. Algunos ejemplos de ello:

  1. ¿Por qué es tan difícil compartir algunos datos en toda la aplicación?

  2. ¿Por qué es tan difícil pasar datos entre componentes? También conocidas props. Las props o propiedades se usan cuando quieres pasar datos entre un padre y un hijo ¿Pero qué pasa si tenemos que ir más lejos? Es un infierno.

  3. ¿¿Redux?? Es demasiado.

La context API está aquí para resolver algunos de esos enigmas:

  1. Tener una aplicación global centralizada: en lugar de limitarte a los estados locales en las vistas, ahora puede compartir datos en un componente principal y sus componentes relativos (hijos, nietos y así). El estado centralizado se llama store y podemos extenderlo/propagarlo utilizando el Context.Provider.

  2. Propagación y re-renderizado de datos: cuando este estado centralizado llamado estado global (store) cambia, desencadena una re-renderización de todos los componentes hijos (tu aplicación completa) lo que genera nuevos datos para mostrar en la UI. Un setState pero central.

  3. Si ya has trabajado con React, probablemente hayas sentido la frustración de pasar propiedades en toda tu aplicación, nosotros lo llamamos el "infierno de propiedades".

¿Cómo funciona la API de contexto?

El concepto detrás es muy simple: hay un solo y gran proveedor que provee información para muchos consumidores, no hay límites en la cantidad de consumidores.

Cada vez que los datos del proveedor cambian, todos los consumidores reciben una notificación. Es muy similar a cómo funciona la señal de TV. Un canal de TV emite una señal de datos y todas las antenas de TV consumen esa señal, reciben el nuevo contenido y renderizan la imagen en los televisores.

Todo el mundo tiene acceso al contexto global ahora.

Explicación Context API

Flujo de datos unidireccional

El store es ahora la pieza más delicada de información de nuestra aplicación, y es muy suceptible a malos usos, es decir, un cambio malo y toda la aplicación se vendrá abajo. Para evitar este posible escenario debemos asegurarnos que la información de nuestro store sea read-only para los consumidores, y que solo pueda actualizarse nuevamente con un conjunto limitado de funciones. Como un state normal, no cambiamos el state, establecemos uno nuevo. Este paradigma arquitectónico se llama Flux.

Flux

Debemos separar el store de las actions y las views (componentes) y asegurarnos de que todas las views o vistas llaman a acciones para actualizar el store. Nunca cambiaremos el store directamente desde una vista. Estoy siendo redundante, lo sé... lo hago a propósito...

Ahora todo junto

  • Vamos a implementar un solo punto de verdad en toda la aplicación: el global state.
  • Este estado contendrá la información y las funciones para establecer un nuevo state: store y actions.
  • Vamos a propagarlo en toda nuestra aplicación utilizando el hook useContext().

Una implementación sencilla

De acuerdo, después de un par de horas para hacer la implementación de la API de contexto más simple sin usar enlaces... ¡Esto es lo que obtuve en 5 pasos simples!:

  • Paso 1 (Crear el contexto): Este paso casi no tiene lógica, simplemente llama a la función createContext desde React. Ese objeto se compartirá con todos los consumidores durante el tiempo de vida de la aplicación, contendrá la aplicación del store y actions.

AppContext.js

1// Paso 1: Define un contexto que se compartirá dentro de toda la aplicación. 2 3import React from 'react'; 4 5const AppContext = React.createContext(null);
  • Paso 2 (Store y actions): Crea un componente ContextWrapper que utilizaremos para pasarle el context (paso 1) a los consumidores. En el estado del ContextWrapper declaramos nuestro global state inicial, que incluye la información (store) y las funciones (actions).

Nota: Debemos importar tanto el AppContext cómo el ContextWrapper.

1// Paso 2: Crea un componente ContextWrapper que debe ser el padre de cada consumidor 2 3import React, { useState } from 'react'; 4 5export const AppContext = React.createContext(null); 6 7export const ContextWrapper = (props) => { 8 const [ store, setStore ] = useState({ 9 todos: ["Make the bed", "Take out the trash"] 10 }); 11 const [ actions, setActions ] = useState({ 12 addTask: title => setStore({ ...store, todos: store.todos.concat(title) }) 13 }); 14 15 return ( 16 <AppContext.Provider value={{ store, actions }}> 17 {props.children} 18 </AppContext.Provider> 19 ); 20}
  • Paso 3 (Vistas): Ahora podemos contener al componente principal dentro del ContextWrapper para que todos sus componentes hijos tengan acceso al Context.Consumer. En este breve ejemplo usaremos el componente <TodoList /> como componente principal (la declaración está en el último paso).

index.js

1// Paso 3: Ubica tu componente principal dentro del contenedor ContextWrapper, 2 3import React from 'react'; 4import ReactDOM from 'react-dom'; 5 6import { ContextWrapper } from 'path/to/AppContext.js'; 7import TodoList from 'path/to/TodoList'; 8 9const MyView = () => ( 10 <ContextWrapper> 11 <TodoList /> 12 </ContextWrapper> 13 ); 14 15ReactDOM.render(<MyView />, document.querySelector("#app"));
  • Paso 4: Ahora podemos crear el componente TodoList sabiendo que podemos usar el hook useContext() para leer el store desde el global state (no se necesitan props). En este caso, el componente renderizará los to-dos y también podrá añadir nuevas tareas a la lista.
1// Paso 4: Declara una variable con el hook useContext(), después úsalo como un objeto para acceder al código interno 2 3import React, { useContext } from 'react'; 4import { AppContext } from 'path/to/AppContext.js'; 5 6export const TodoList = () => { 7 const context = useContext(AppContext) 8 return <div> 9 {context.store.todos.map((task, i) => (<li key={i}>{task}</li>))} 10 <button onClick={() => context.actions.addTask("I am the task " + context.store.todos.length)}> + add </button> 11 </div> 12}

Muy seguido veremos el hook useContext del ejemplo de arriba

1const context = useContext(AppContext); 2return <div> 3 {context.store.todos.map((task, i) => (<li key={i}>{task}</li>))} 4 <button onClick={() => context.actions.addTask("I am the task " + context.store.todos.length)}> + add </button> 5</div>

En su variante desestructurada. Presta atención a cómo eso también simplifica la forma en que accedemos al store:

1const {store, actions} = useContext(AppContext); 2return <div> 3 {store.todos.map((task, i) => (<li key={i}>{task}</li>))} 4 <button onClick={() => actions.addTask("I am the task " + store.todos.length)}> + add </button> 5</div>

Prueba el código en vivo