Curso de React.js

¿Qué es React Context?

Curso de React.js

Contenido del curso

Herramientas avanzadas: escalabilidad, organización y persistencia

¿Qué es React Context?

Resumen

React Context resuelve uno de los dolores más comunes al construir aplicaciones con React: el famoso prop drilling. Si trabajas con componentes anidados en varios niveles, esta herramienta te permite crear un estado global y comunicar componentes sin pasar propiedades de padre a hijo a nieto.

Qué es el prop drilling y por qué te complica la vida

Imagina la estructura típica de una app de tareas. Tienes un componente App que llama a TodoCounter, TodoSearch, TodoList y CreateTodoButton. A su vez, TodoList llama a TodoItem. Hasta ahí todo bien, pero la comunicación entre ellos se hace con props, y eso se vuelve un laberinto.

El componente App envía propiedades a TodoCounter, otras distintas a TodoSearch, otras a TodoList, y este último vuelve a pasarlas al TodoItem. Cuando un componente actualiza el estado, ese cambio se propaga hacia arriba y luego baja a otros componentes que ni siquiera son sus hijos directos. Ese flujo enredado es el prop drilling, y en aplicaciones grandes como Platzi, Google o GitHub se vuelve insostenible.

¿Qué es el prop drilling? Es cuando una propiedad atraviesa múltiples niveles de componentes solo para llegar al que realmente la necesita, aunque los intermedios no la usen. [01:32]

Cómo cambia React Context la forma de pensar la app

En lugar de ver tus componentes como un árbol con abuelos, padres e hijos, React Context te invita a verlos como piezas independientes que se conectan directamente al estado global. Cada componente le pide al contexto solo la información que necesita, sin importar en qué nivel esté.

Cómo identificar el problema en tu propio código

En una app real, el componente App suele traer datos desde un custom hook como useLocalStorage, crear estados, definir efectos y actualizadores, y luego entregar todo a un componente como AppUI. El costo de separar lógica e interfaz es que AppUI recibe un montón de props que no usa directamente, sino que reenvía a sus hijos. [04:15]

Por ejemplo, AppUI recibe completedTodos y totalTodos solo para pasárselos a TodoCounter. Recibe searchValue y setSearchValue únicamente para entregárselos a TodoSearch. Esa cadena de reenvíos es el síntoma claro de que necesitas un contexto.

Qué propiedades sí pertenecen al componente y cuáles no

Dentro de AppUI realmente se usan loading, error, searchedTodos, completeTodo y deleteTodo. El resto solo está de paso. Ese filtro mental te ayuda a decidir qué mover al contexto: todo aquello que un componente reenvía sin usar.

Cómo crear un contexto con React.createContext

El primer paso es crear una carpeta llamada TodoContext dentro de src y un archivo index.js. Allí importas React y usas la herramienta React.createContext() para inicializar tu contexto. [09:42]

javascript import React from 'react';

const TodoContext = React.createContext();

Este contexto expone dos componentes internos: TodoContext.Provider y TodoContext.Consumer. El Provider entrega la información, el Consumer la recibe. Puedes usarlos directamente, pero la práctica más limpia es crear tu propio Provider personalizado.

¿Para qué sirve React.createContext? Crea un objeto de contexto que incluye un Provider y un Consumer, los dos componentes con los que compartes y consumes datos globales en tu app. [10:18]

Cómo construir un TodoProvider personalizado

En vez de exportar TodoContext.Provider directamente, defines un componente TodoProvider que envuelve al Provider y encapsula toda la lógica que antes vivía en el componente App.

  • Mueves la llamada a useLocalStorage al TodoProvider.
  • Trasladas los estados, estados derivados y actualizadores.
  • Expones todo en la prop value del Provider.
  • Recibes props.children para insertar cualquier componente dentro.

Este patrón te da tres beneficios: un nombre más cómodo sin puntos intermedios, la posibilidad de exportarlo como un componente común, y un lugar único para centralizar la lógica compartida.

javascript function TodoProvider({ children }) { // toda la lógica de estados y actualizadores return ( <TodoContext.Provider value={{ loading, error, searchedTodos, completeTodo, deleteTodo }}> {children} </TodoContext.Provider> ); }

Cómo consumir el contexto con TodoContext.Consumer

Una vez envuelves tu AppUI dentro del TodoProvider en el componente App, cualquier hijo puede acceder al contexto. Para leerlo usas TodoContext.Consumer, que sigue un patrón llamado render props. [16:50]

Esto significa que el Consumer no espera componentes directos como hijos, sino una función que recibe el value del contexto y retorna los elementos a renderizar.

javascript <TodoContext.Consumer> {({ loading, error, searchedTodos, completeTodo, deleteTodo }) => ( <TodoList> {/* render de los todos */} </TodoList> )} </TodoContext.Consumer>

Por qué se llaman render functions

La función que pasas como hijo al Consumer recibe como parámetro el objeto que guardaste en value. Desde ahí desestructuras solo lo que necesitas. Es la forma en que React conecta el dato global con el árbol de componentes sin romper la convención de JSX.

¿Cuándo usar Provider y cuándo Consumer? El Provider envuelve a los componentes que comparten el estado. El Consumer se usa dentro de cualquier componente hijo que quiera leer ese estado.

Qué pasa con TodoCounter y TodoSearch

Al quitar las props a TodoCounter y TodoSearch, esos componentes dejan de funcionar temporalmente. Buscan totalTodos, completedTodos, searchValue y setSearchValue, pero ya no los reciben. La solución es consumir el contexto desde adentro de cada uno.

El TodoContext.Consumer funciona y lo encontrarás en muchos proyectos profesionales de React, pero existe una forma más cómoda de consumir ese contexto sin anidar funciones dentro de funciones. ¿Has usado ya useContext en tus proyectos? Cuéntame en los comentarios cómo organizas tus contextos.