Aprenda el contexto de React en 5 minutos: un tutorial para principiantes

La API de contexto de React se ha convertido en la herramienta de administración de estado elegida por muchos, muchas veces reemplazando a Redux por completo. En este tutorial rápido de 5 minutos, verá una introducción a lo que es Contexto y cómo usarlo.

Si desea una introducción adecuada a este tema, puede unirse a la lista de espera para mi próximo curso avanzado de React, o si aún es un principiante, consulte mi curso introductorio gratuito sobre React.

Considere este árbol, en el que los cuadros inferiores representan componentes separados:

Árbol de componentes

Podemos agregar fácilmente el estado a los componentes inferiores, pero hasta ahora la única forma de pasar datos al hermano de un componente era mover el estado a un componente superior y luego pasarlo al hermano a través de accesorios.

Pasando datos a través de accesorios

Si luego descubrimos que el hermano del componente con estado también necesita los datos, tenemos que levantar el estado nuevamente y volver a pasarlo:

Pasando el estado a través de múltiples niveles

Si bien esta solución funciona, los problemas comienzan si un componente de una rama diferente necesita los datos:

Un componente más distante requiere datos

En este caso, necesitamos pasar el estado desde el nivel superior de la aplicación a través de todos los componentes intermedios al que necesita los datos en la parte inferior, aunque los niveles intermedios no los necesiten. Este proceso tedioso y lento se conoce como perforación de hélice .

Perforación de hélice

Aquí es donde entra la API de contexto. Proporciona una forma de pasar datos a través del árbol de componentes a través de un par Proveedor-Consumidor sin tener que pasar accesorios a través de cada nivel. Piense en ello como los componentes que juegan Catch con datos: los componentes intermediarios pueden ni siquiera "saber" que está sucediendo algo:

Contexto en acción

Para demostrar esto, crearemos esta imagen de cambio de día a noche funky (y súper útil).

Si desea ver el código completo, asegúrese de consultar el área de juegos de Scrimba para ver este artículo.

Crear contexto

Para empezar, creamos un nuevo contexto. Como queremos que toda la aplicación tenga acceso a esto, vamos index.jsy ajustamos la aplicación ThemeContext.Provider.

También pasamos el valueaccesorio a nuestro Proveedor. Contiene los datos que queremos guardar. Por ahora, solo codificamos 'Day'.

import React from "react"; import ReactDOM from "react-dom"; import ThemeContext from "./themeContext"; import App from "./App"; ReactDOM.render(   , document.getElementById("root") ); 

Consumir Context con contextType

Actualmente, en App.js, simplemente devolvemos el componente.

import React from "react"; import Image from "./Image"; class App extends React.Component { render() { return ( ); } } export default App; 

Nuestro objetivo es utilizar Context para cambiar los classNames Image.jsde Daya Night, dependiendo de la imagen que queramos representar. Para hacer esto, agregamos una propiedad estática a nuestro componente llamado ContextTypey luego usamos la interpolación de cadenas para agregarlo a los classNames en el componente.

Ahora, los classNames contienen la cadena del valueprop. Nota: me he movido ThemeContexta su propio archivo para evitar un error.

import React from "react"; import Button from "./Button"; import ThemeContext from "./themeContext"; class Image extends React.Component { render() { const theme = this.context; return ( ); } } Image.contextType = ThemeContext; export default Image; 

Contexto Consumidor

Desafortunadamente, este enfoque solo funciona con componentes basados ​​en clases. Si ya ha aprendido sobre Hooks en React, sabrá que podemos hacer casi cualquier cosa con componentes funcionales en estos días. Entonces, para una buena medida, deberíamos convertir nuestros componentes en componentes funcionales y luego usar el ThemeContext.Consumercomponente para pasar información a través de la aplicación.

Esto se hace envolviendo nuestros elementos en una instancia de y dentro de eso (donde el childrenir), proporcionando una función que devuelve los elementos. Esto usa el patrón "render prop" donde proporcionamos una función regular como un niño que devuelve algo de JSX para renderizar.

import React from "react"; import Button from "./Button"; import ThemeContext from "./themeContext"; function Image(props) { // We don't need this anymore // const theme = this.context return (  {theme => ( )}  ); } // We don't need this anymore // Image.contextType = ThemeContext; export default Image; 

Nota: También necesitamos envolver el componente , esto nos permite agregar funcionalidad al botón más adelante.

import React from "react"; import ThemeContext from "./themeContext"; function Button(props) { return (  {context => (  Switch  ?   ?   )}  ); } export default Button; 

Proveedor de contexto de extracción

Actualmente estamos pasando un valor codificado de forma rígida a través del Proveedor, sin embargo, nuestro objetivo es cambiar entre la noche y el día con nuestro botón.

Esto requiere mover nuestro proveedor a un archivo separado y colocarlo en su propio componente, en este caso llamado ThemeContextProvider.

import React, { Component } from "react"; const { Provider, Consumer } = React.createContext(); class ThemeContextProvider extends Component { render() { return {this.props.children}; } } export { ThemeContextProvider, Consumer as ThemeContextConsumer }; 

Nota: la propiedad de valor ahora se maneja en el nuevo archivo ThemeContext.js y, por lo tanto, debe eliminarse de index.js.

Cambio de contexto

Para conectar el botón, primero agregamos estado a ThemeContextProvider:

import React, { Component } from "react"; const { Provider, Consumer } = React.createContext(); // Note: You could also use hooks to provide state and convert this into a functional component. class ThemeContextProvider extends Component { state = { theme: "Day" }; render() { return {this.props.children}; } } export { ThemeContextProvider, Consumer as ThemeContextConsumer }; 

A continuación, agregamos un método para cambiar entre día y noche:

toggleTheme = () => { this.setState(prevState => { return { theme: prevState.theme === "Day" ? "Night" : "Day" }; }); }; 

Ahora cambiamos nuestra valuepropiedad a this.state.themepara que devuelva la información del estado.

 render() { return {this.props.children}; } } 

Next, we change value to an object containing {theme: this.state.theme, toggleTheme: this.toggleTheme}, and update all the places where we use a single value to look for theme in an object. This means that every theme becomes context and every reference to theme as value becomes context.theme.

Finally, we tell the button to listen for the onClick event and then fire context.toggleTheme - this updates the Consumers which are using the state from the Provider. The code for the button looks like this:

import React from "react"; import { ThemeContextConsumer } from "./themeContext"; function Button(props) { return (  {context => (  Switch  ?   ?   )}  ); } export default Button; 

Our button now switches the image between night and day in one click!

Context caveats

Like all good things in code, there are some caveats to using Context:

  • Don't use Context to avoid drilling props down just one or two layers. Context is great for managing state which is needed by large portions of an application. However, prop drilling is faster if you are just passing info down a couple of layers.

  • Avoid using Context to save state that should be kept locally. So if you need to save a user's form inputs, for example, use local state and not Context.

  • Always wrap the Provider around the lowest possible common parent in the tree - not the app's highest-level component. No need for overkill.

  • Lastly, if you pass an object as your value prop, monitor performance and refactor as necessary. This probably won't be needed unless a drop in performance is noticeable.

Wrap up

Este ejemplo es bastante simple y probablemente sería más fácil poner el estado en la aplicación y pasarlo a través de accesorios. Sin embargo, es de esperar que muestre el poder de tener consumidores que pueden acceder a los datos independientemente de los componentes que están encima de ellos en el árbol.

Para obtener más información sobre React Context y otras excelentes funciones de React, puede unirse a la lista de espera para mi próximo curso avanzado de React. O si está buscando un más amigable para principiantes, puede consultar mi curso introductorio gratuito sobre React.

Feliz codificación :)