Contextos como Proveedores

Compartir valores contextuales entre componentes anidados al proveedor

Dragon Nomada
React Adventure
5 min readFeb 23, 2021

--

Se muestra el servicio de mensajería DHL, que representa un proveedor de paquetes, entre múltiples usuarios. Tomada de https://unsplash.com/photos/mEF00fo9YFE

Es momento de atacar otro de los hooks más importantes de React, el hook de contextos — useContext, que nos permitirá compartir un valor, entre múltiples componentes anidados, sin importar el nivel de anidación, siempre y cuándo se encuentren dentro del proveedor. Esto suele ser útil, para compartir valores y estados entre múltiples componentes, sin tener que enviar los valores como entradas y salidas mediante propiedades.

El uso de contextos debe ser cuidadoso y preciso, ya que cada que cambie un valor en el contexto, este mandará a renderizar los componentes que hagan uso de este valor, por lo que es muy común bajar el rendimiento de nuestras aplicaciones. Sin embargo, cuándo los valores no cambian tanto o su dependencia entre múltiples componentes es alta, conviene su uso, para de este modo, acceder a valores compartidos ente todos.

Algo común es compartir estados y ajustadores, reductores y despachadores, valores y funciones personalizadas de ajuste e interfaces de programación optimizadas mediante hooks personalizados.

La instancia del contexto

Un contexto se crea mediante React.context, este devolverá una instancia al contexto, que podrá ser utilizada por el hook useContext, de modo que cualquier componente pueda acceder al valor provisto de la instancia. La instancia relaciona el componente Provider y el componente Consumer, los cuáles permitirán proveer el contexto y consumirlo directamente.

Sintaxis

const MyContext = React.createContext(defaultValue);

Donde MyContext es la instancia del contexto y defaultValue el valor por defecto, en caso de que el proveedor no especifique uno.

Proveedor del contexto

El proveedor del contexto, es un componente, que establece el valor a compartir en el contexto, y anida a todos los componentes que tengan alcance a este valor. El concepto es similar, a que el proveedor crea una habitación, dónde se está compartiendo un valor, y todos los componentes dentro de la habitación, tendrán acceso al valor compartido. Cuándo el valor del proveedor cambia, todos dentro de la habitación, serán notificados, para que se vuelvan a pintar.

Sintaxis

<MyContext.Provider value={valor compartido}>

...componentes con alcance al valor del contexto, habitación

</MyContext.Provider>

Donde MyContext.Provider es el componente proveedor, de la instancia MyContext. Este componente anida a todos los otros componentes, formando una habitación, dónde, cada componente dentro de la habitación, tendrá acceso al valor del contexto mediante useContext y se volverá a pintar, cuándo el contexto cambie.

Consumidor del contexto

Un consumidor directo del contexto, es un componente que anida una función de consumo del valor del contexto, y devuelve la vista adecuada, según ese valor. Es útil cuándo no se quiere formalizar algún componente, y ahorrar el consumo del hook useContext, no es recomendable.

Sintaxis

<MyContext.Provider value={myValue}>

...

<MyContext.Consumer>

{ myValue => { ...(devuelve interfaz) } }

</MyContext.Consumer>

...

</MyContext.Provider>

Donde MyContext.Consumer es el componente especial de consumo, que recibe la función de consumo, cuyo parámetro es el valor compartido myValue del contexto, y devuelve la interfaz adecuada para pintarse o null.

Consumir el contexto dentro de un componente

Finalmente, los componentes, que se encuentren anidados en un proveedor, en cualquier nivel de anidación, tendrán acceso al valor compartido en el contexto, mediante el hook useContext.

Sintaxis

function MyComponent() {

const value = useContext(MyContext);

}

Donde value es el valor contextual y MyContext es la instancia creada del contexto.

Ejemplo

En el siguiente ejemplo, se observa la creación de un contexto sencillo, que retiene el número de clics.

  1. Observa que se crea una instancia de un contexto, con el valor por defecto { clicks, setClicks }, donde se observa, que setClicks es una función aún no implementada
  2. Observa que se define el componente ClickButton, que accede al valor del contexto, mediante useContext(ClicksContext).
  3. Observa que el valor del contexto devuelto, llamado context, contiene context.clicks y context.setClicks. Los cuáles son utilizados, para acceder al valor de los clics y ajustarlos.
  4. Observa que en el componente App, se define un estado [clicks, setClicks] que retendrá los clics.
  5. Observa la creación de un proveedor mediante ClickContext.Provider, el cuál anida un consumidor ClicksContext.Consumer y un componente llamado ClickButton.
  6. Observa que el valor asignado a <ClickContext.Provider value={...}>, es un objeto con las claves { clicks, setClicks }, y se asocian a las variables del esto [clicks, setClicks]. Es decir, el valor del proveedor, es el estado clicks-setClicks.
  7. Observa que el consumidor <ClicksContext.Consumer>, anida una función que recibe como parámetro el valor del contexto context. De él se accede a context.clicks para devolver un <span> como interfaz.
  8. Observa que se monta el componente <ClickButton>, que muestra el botón, que al ser pulsado, incrementa el número de clics, mediante context.setContext(context.clicks + 1). Este manda a actualizar el valor del estado clicks-setClicks, y finalmente, el proveedor actualiza el valor del contexto.

Proyecto — Login Lock Context

En este proyecto, vemos el uso de los contexto, para crear un componente que bloquee a los componentes hijos anidados. De modo, que hasta que no se inicie sesión, muestre un formulario de bloqueo.

Revisa cuidadosamente la estructura del proyecto, la organización del código, el formulario independiente al contexto, la salida del formulario props.onSignIn y la forma segura de consumirlo. Revisa también el hook personalizado useLoginLock. La interfaz devuelta, la creación de un proveedor formalizado, el consumo del formulario. Y finalmente, revisa en App.js el uso del proveedor y sus resultados.

Conclusiones

Hemos aprendido a utilizar el hook de contextos, el cuál nos permite compartir un valor, mediante un proveedor, que informará los cambios sobre el valor compartido, a todos los componentes anidados. Esto será útil, cuando queramos compartir valores que no cambien mucho, o que sea utilizado en demasiados componentes.

Los contextos, evitan que estemos propagando los valores de un componente a otro, y crear más bien una especie de habitación, dónde todos los elementos anidados en la habitación, tendrán acceso al valor del contexto.

Debemos tener cuidado en su uso, y limitarlo a casos especiales, dónde su conveniencia sea bastante útil, por ejemplo, cuándo los valores compartidos no cambien mucho, como en la paleta de colores de la aplicación, inicios de sesión, carritos de compra, y demás bolsas de valores compartidos, que cambian, conforme el usuario interactúa con la aplicación, y no lo hacen automáticamente, como en contadores y así. Un segundo caso opcional dónde podremos usar contextos, es cuándo aunque los valores cambien mucho, será necesario compartirlos a través de gran cantidad de componentes, por ejemplo, una transacción en tiempo real, un chat, una tabla en tiempo real, etc.

--

--

Dragon Nomada
React Adventure

I love maths, algorithms, artificial intelligence, data science and zen's philosophy