
Profundizando en el contexto de React

Es posible que últimamente se haya preguntado a qué se debe todo ese revuelo sobre Context y qué podría significar para usted y sus sitios React. Antes de Contexto, cuando la gestión del estado se complicaba más allá de la funcionalidad de setState
, probablemente tenías que utilizar una biblioteca de terceros. Gracias a las actualizaciones recientes del increíble equipo de React, ahora tenemos Contexto que podría ayudar con algunos problemas de administración del estado.
¿Qué resuelve el contexto?
¿Cómo se mueve el estado de un componente principal a un componente secundario anidado en el árbol de componentes? Sabes que puedes usar Redux para administrar el estado, pero no deberías tener que saltar a Redux en cada situación.
Hay una manera de hacer esto sin Redux ni ninguna otra herramienta de administración de estado de terceros. ¡Puedes usar accesorios!
Digamos que la característica que desea implementar tiene una estructura de árbol similar a la que tengo a continuación:
El estado reside en el componente de la aplicación y es necesario en los componentes UserProfile y UserDetails . Debes pasarlo mediante accesorios por el árbol. Si los componentes que necesitan este estado tienen 10 pasos de profundidad, esto puede resultar tedioso, agotador y propenso a errores. Se supone que cada componente es como una caja negra: otros componentes no deberían ser conscientes de estados que no necesitan. A continuación se muestra un ejemplo de una aplicación que coincide con el escenario anterior.
class App extends React.Component { state = { user: { username: 'jioke', firstName: 'Kingsley', lastName: 'Silas' } } render() { return( div User user={this.state.user} / /div ) }}const User = (props) = ( div UserProfile {...props.user} / /div)const UserProfile = (props) = ( div h2Profile Page of {props.username}/h2 UserDetails {...props} / /div)const UserDetails = (props) = ( div pUsername: {props.username}/p pFirst Name: {props.firstName}/p pLast Name: {props.lastName}/p /div)ReactDOM.render(App /, document.getElementById("root"));
Pasamos el estado de un componente a otro usando accesorios. El componente Usuario no necesita el estado, pero tiene que recibirlo a través de accesorios para poder bajar del árbol. Esto es exactamente lo que queremos evitar.
¡Contexto al rescate!
La API de contexto de React le permite almacenar el estado en lo que parece un estado global de la aplicación y acceder a él solo en los componentes que los necesitan, sin tener que profundizar en él mediante accesorios.
Comenzamos a iniciar un nuevo contexto usando React.createContext()
const UserContext = React.createContext({})const UserProvider = UserContext.Providerconst UserConsumer = UserContext.Consumer
Este nuevo Contexto se asigna a una const
variable, en este caso, la variable es UserContext . Puede ver que ahora no es necesario instalar una biblioteca que createContext()
esté disponible en React (16.3.0 y superior).
El componente Proveedor pone el contexto a disposición de los componentes que lo necesitan, que se denominan Suscriptores. En otras palabras, el componente Proveedor permite a los Consumidores suscribirse a cambios de contexto. Recuerde que el contexto es similar al estado de una aplicación global. Por lo tanto, los componentes que no sean Consumidores no estarán suscritos al contexto.
Si está codificando localmente, su archivo de contexto se verá así:
import { createContext } from 'react'const UserContext = createContext({})export const UserProvider = UserContext.Providerexport const UserConsumer = UserContext.Consumer
El proveedor
Usaremos el Proveedor en nuestro componente principal, donde tenemos nuestro estado.
class App extends React.Component { state = { user: { username: 'jioke', firstName: 'Kingsley', lastName: 'Silas' } } render() { return( div UserProvider value={this.state.user} User / /UserProvider /div ) }}
El Proveedor acepta que se le pase una propuesta de valor a sus descendientes de los componentes del Consumidor. En este caso, pasaremos el estado de usuario a los componentes del consumidor. Se puede ver que no estamos pasando el estado al componente Usuario como accesorios. Eso significa que podemos editar el componente Usuario y excluir los accesorios ya que no los necesita:
const User = () = ( div UserProfile / /div)
El consumidor
Varios componentes pueden suscribirse a un componente de proveedor. Nuestro componente UserProfile necesita hacer uso del contexto, por lo que se suscribirá a él.
const UserProfile = (props) = ( UserConsumer {context = { return( div h2Profile Page of {context.username}/h2 UserDetails / /div ) }} /UserConsumer)
Los datos que inyectamos en el proveedor a través de la propuesta de valor luego están disponibles en el parámetro de contexto de la función. Ahora podemos usar este acceso al nombre de usuario del usuario en nuestro componente.
El componente UserDetails tendrá un aspecto similar al componente UserProfile ya que es suscriptor del mismo proveedor:
const UserDetails = () = ( div UserConsumer {context = { return ( div pUserame: {context.username}/p pFirst Name: {context.firstName}/p pLast Name: {context.lastName}/p /div ) }} /UserConsumer /div)
Estado de actualización
¿Qué pasa si queremos permitir que los usuarios cambien su nombre y apellido? Eso también es posible. Los componentes del consumidor pueden volver a representar siempre que haya cambios en el valor pasado por el componente del proveedor. Veamos un ejemplo.
Tendremos dos campos de entrada para el nombre y apellido en el componente del consumidor. Desde el componente Proveedor tendremos dos métodos que actualicen el estado de la aplicación utilizando los valores ingresados en los campos de entrada. ¡Basta de hablar, codificamos!
Nuestro componente de aplicaciones se verá así:
class App extends React.Component { state = { user: { username: 'jioke', firstName: 'Kingsley', lastName: 'Silas' } } render() { return( div UserProvider value={ { state: this.state.user, actions: { handleFirstNameChange: event = { const value = event.target.value this.setState(prevState = ({ user: { ...prevState.user, firstName: value } })) }, handleLastNameChange: event = { const value = event.target.value this.setState(prevState = ({ user: { ...prevState.user, lastName: value } })) } } } } User / /UserProvider /div ) }}
Estamos pasando un objeto que contiene estado y acciones a los accesorios de valor que recibe el Proveedor. Las acciones son métodos que se activarán cuando onChange
ocurra un evento. Luego, el valor del evento se utiliza para actualizar el estado. Dado que queremos actualizar el nombre o el apellido, es necesario preservar el valor del otro. Para ello hacemos uso del Operador Spread ES6, que nos permite actualizar el valor de la clave especificada.
Con los nuevos cambios, necesitamos actualizar el componente UserProfile .
const UserProfile = (props) = ( UserConsumer {({state}) = { return( div h2Profile Page of {state.username}/h2 UserDetails / /div ) }} /UserConsumer)
Usamos la desestructuración de ES6 para extraer el estado del valor recibido del proveedor.
Para el componente UserDetails , utilizamos tanto el estado como las acciones. También necesitamos agregar dos campos de entrada que escucharán un onChange()
evento y llamarán a los métodos correspondientes.
const UserDetails = () = { return ( div UserConsumer {({ state, actions }) = { return ( div div pUserame: {state.username}/p pFirst Name: {state.firstName}/p pLast Name: {state.lastName}/p /div div div input type="text" value={state.firstName} onChange={actions.handleFirstNameChange} / /div div input type="text" value={state.lastName} onChange={actions.handleLastNameChange} / /div /div /div ) }} /UserConsumer /div )}
Usar valores predeterminados
Es posible pasar valores predeterminados al inicializar Context. Para hacer esto, en lugar de pasarle un objeto vacío createContext()
, le pasaremos algunos datos.
const UserContext = React.createContext({ username: 'johndoe', firstName: 'John', lastName: 'Doe'})
Para hacer uso de estos datos en nuestro árbol de aplicaciones, debemos eliminar el proveedor del árbol. Entonces nuestro componente de aplicaciones se verá así.
class App extends React.Component { state = { user: { username: 'jioke', firstName: 'Kingsley', lastName: 'Silas' } } render() { return( div User / /div ) }}
Los datos que se utilizarán en los componentes del Consumidor se definirán cuando inicialicemos un nuevo Contexto.
En conclusión
Cuando las cosas se complican y tienes la tentación de ejecutar yarn install [insert third-party library for state management]
, haz una pausa por un segundo: tienes React Context listo. ¿No me crees? Quizás le creas a Kent C. Dodds.
Deja una respuesta