¿Cómo utilizar el Hook useContext? Comunicación de componentes funcionales

¿Cómo utilizar el Hook useContext? Comunicación de componentes funcionales
Juan Carlos G2020-09-29

Hola viajero, hoy vamos a ver el funcionamiento del Hook useContext, con el cual podrás manipular el contexto de tus componentes funcionales y, así, comunicarlos tal y como lo hacemos a través de API Context.

En esta clase lo que vamos hacer es actualizar el ejemplo que hicimos en el capítulo de API Context, así que, te dejo el link a ese post por si no lo has visto y puedas comprender mejor esta clase.

 

📌 Suscríbete a mi canal y activa la campanita para que no te pierdas ningún video 🤘

 

¿Qué aprenderás de useContext?

  • Declaración de useContext.
  • Migrar de API Context en su forma tradicional a Hooks en componentes funcionales.
  • Comprobarás que al utilizar este Hook, tu código será más compacto y fácil de leer.

 

 

Repositorio

  • Puedes descargar el código dando clic aquí.
  • O puedes clonar el repositorio y cambiarte a la rama "usecontext".
git clone https://github.com/EWebik/react-js.git
git checkout usecontext

 

¿Qué es y para qué sirve el Hook useContext?

Al useContext lo podemos definir como un Hook que permite comunicar componentes funcionales a través del contexto en React.

Entonces, este Hook recibe un objeto de contexto y retorna el valor del contexto actual, el cual si recordamos un poco, el valor del contexto actual lo asignamos a través de value en el provider:

<MyContext.Provider value={value}>

 

Declaración de useContext

Como otros Hooks que ya hemos visto, lo podemos declarar dentro de hilo principal de nuestro componente.

const context = useContext();

 

Uso correcto de useContext

Ahora, recuerda que useContext debe recibir el contexto como argumento y, además, podemos obtener a través de desestructuración, el valor del contexto.

const context = useContext(Context);

O

const {mensaje, index, actualizarMensaje} = useContext(Context);

 

Uso incorrecto de useContext

Cuando utilicemos este Hook debes pasarle como argumento la variable de conexto como tal y nunca pasar el provider o el consumer. Aquí algunos ejemplos incorrectos de su uso.

useContext(MyContext.Consumer)
useContext(MyContext.Provider)

📌 Nota: Recuerda que al agregar useContext a tu componente funcional, este siempre se volverá a renderizar cuando el contexto cambié.

 

Ejemplo de useContext

Bien, hagamos un ejemplo con este Hook, lo que vamos hacer es migrar API Context a useContext, y lo vamos hacer utilizando el código que desarrollamos en el capítulo 9 de este curso de React JS. Este es el código que hicmos.

Ejemplo de useContext

En dicho ejemplo lo que hicimos fue comunicar nuestros componentes a través de API Context, solo que ahora implementaremos useContext en el componente Hijo1, para que veas en acción a este Hook.

Comencemos revisando el código original y el que vamos a modificar.

import React,{useState,useRef} from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

//Introducción API Context React

//DECLARACIÓN
const {Provider, Consumer} = React.createContext();


const Hijo1 = (props)=>{
  return(
    <Consumer>
      {
        ({mensaje, index, actualizarMensaje}) =>(
          <div className="hijo">
            <h2>Hijo 1</h2>
            {
              mensaje !== "" ?(
                <p className={
                  index === 0 ? 'colorPadre':
                  index === 1 ? 'colorHijo1':
                  index === 2 ? 'colorHijo2':''
                }>{
                  ((index === 0 ? 'Padre dice:':
                    index === 1 ? 'Hijo 1 dice:':
                    index === 2 ? 'Hijo 2 dice:':'')
                    + ' ' + mensaje)
                }</p>
              ):("")
            }
            <textarea
              rows="5"
              onChange={(e)=>{
                actualizarMensaje(e,1);
              }} />
          </div>
        )
      }
    </Consumer>
  )
}

const Hijo2 = (props)=>{
  return(
    <Consumer>
    {
      ({mensaje, index, actualizarMensaje}) =>(
        <div className="hijo">
          <h2>Hijo 2</h2>
          {
            mensaje !== "" ?(
              <p className={
                index === 0 ? 'colorPadre':
                index === 1 ? 'colorHijo1':
                index === 2 ? 'colorHijo2':''
              }>{
                ((index === 0 ? 'Padre dice:':
                  index === 1 ? 'Hijo 1 dice:':
                  index === 2 ? 'Hijo 2 dice:':'')
                  + ' ' + mensaje)
              }</p>
            ):("")
          }
          <textarea
            rows="5"
            onChange={(e)=>{
              actualizarMensaje(e,2);
            }} />
        </div>
      )
    }
    </Consumer>
  )
}

class Padre extends React.Component{
  constructor(props){
    super(props)
    this.state={
      mensaje:"",
      index:0
    }
  }

  actualizarMensaje = (e, index)=>{
    const {value} = e.target;
    this.setState({
      ...this.state,
      mensaje:value,
      index
    })
  }

  render(){
    return(
      <Provider value={{
        mensaje: this.state.mensaje,
        index: this.state.index,
        actualizarMensaje:this.actualizarMensaje
      }}>
        <div className="padre">
          <h1>EWebik - API Context</h1>
          {
            this.state.mensaje !== "" ?(
              <p className={
                this.state.index === 0 ? 'colorPadre':
                this.state.index === 1 ? 'colorHijo1':
                this.state.index === 2 ? 'colorHijo2':''
              }>{
                ((this.state.index === 0 ? 'Padre dice:':
                  this.state.index === 1 ? 'Hijo 1 dice:':
                  this.state.index === 2 ? 'Hijo 2 dice:':'')
                  + ' ' + this.state.mensaje)
              }</p>
            ):("")
          }
          <textarea
            rows="5"
            onChange={(e)=>{
              this.actualizarMensaje(e,0);
            }} />
          <div className="hijos">
            <Hijo1 />
            <Hijo2 />
          </div>
        </div>
      </Provider>
    )
  }
}

ReactDOM.render(
  <Padre />,
  document.getElementById('root')
);

 

  1. Lo primero que vamos hacer es redefinir la declaración de context:
//Cambiar de
const {Provider, Consumer} = React.createContext();

//Por
const Context = React.createContext();

 

  1. Utilizando notación de punto, agregamos el nuevo marcado a nuestro componentes: Padre e Hijo2.
class Padre extends React.Component{
  
  ...

  render(){
    return(
      <Context.Provider value={{
        mensaje: this.state.mensaje,
        index: this.state.index,
        actualizarMensaje:this.actualizarMensaje
      }}>
        ...
      </Context.Provider>
    )
  }
}

 

const Hijo2 = (props)=>{
  return(
    <Context.Consumer>
    {
      ({mensaje, index, actualizarMensaje}) =>(
        ...
      )
    }
    </Context.Consumer>
  )
}

 

  1. Mientras tanto en el componente Hijo3, vamos a agregar useConext con lo cual migramos API Context en su forma tradicional a Hooks.
const Hijo1 = (props)=>{
  const {mensaje, index, actualizarMensaje} = useContext(Context);
  return(
    <div className="hijo">
      <h2>Hijo 1</h2>
      {
        mensaje !== "" ?(
          <p className={
            index === 0 ? 'colorPadre':
            index === 1 ? 'colorHijo1':
            index === 2 ? 'colorHijo2':''
          }>{
            ((index === 0 ? 'Padre dice:':
              index === 1 ? 'Hijo 1 dice:':
              index === 2 ? 'Hijo 2 dice:':'')
              + ' ' + mensaje)
          }</p>
        ):("")
      }
      <textarea
        rows="5"
        onChange={(e)=>{
          actualizarMensaje(e,1);
        }} />
    </div>
  )
}
  • En primer lugar vemos que dentro del hilo principal agregamos el Hook.
const {mensaje, index, actualizarMensaje} = useContext(Context);
  • Eliminamos el marcado de API Context
<Context.Consumer>
    {
      ({mensaje, index, actualizarMensaje}) =>(
      
      ...
  
       }   
</Context.Consumer>
  

Con estos imples cambios hacemos nuestro componente más compacto y fácil de leer.

 

Aquí el código completo

import React,{useState,useRef, useContext} from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

//Hook useContext

//DECLARACIÓN
const Context = React.createContext();


const Hijo1 = (props)=>{
  const {mensaje, index, actualizarMensaje} = useContext(Context);
  return(
    <div className="hijo">
      <h2>Hijo 1</h2>
      {
        mensaje !== "" ?(
          <p className={
            index === 0 ? 'colorPadre':
            index === 1 ? 'colorHijo1':
            index === 2 ? 'colorHijo2':''
          }>{
            ((index === 0 ? 'Padre dice:':
              index === 1 ? 'Hijo 1 dice:':
              index === 2 ? 'Hijo 2 dice:':'')
              + ' ' + mensaje)
          }</p>
        ):("")
      }
      <textarea
        rows="5"
        onChange={(e)=>{
          actualizarMensaje(e,1);
        }} />
    </div>
  )
}

const Hijo2 = (props)=>{
  return(
    <Context.Consumer>
    {
      ({mensaje, index, actualizarMensaje}) =>(
        <div className="hijo">
          <h2>Hijo 2</h2>
          {
            mensaje !== "" ?(
              <p className={
                index === 0 ? 'colorPadre':
                index === 1 ? 'colorHijo1':
                index === 2 ? 'colorHijo2':''
              }>{
                ((index === 0 ? 'Padre dice:':
                  index === 1 ? 'Hijo 1 dice:':
                  index === 2 ? 'Hijo 2 dice:':'')
                  + ' ' + mensaje)
              }</p>
            ):("")
          }
          <textarea
            rows="5"
            onChange={(e)=>{
              actualizarMensaje(e,2);
            }} />
        </div>
      )
    }
    </Context.Consumer>
  )
}

class Padre extends React.Component{
  constructor(props){
    super(props)
    this.state={
      mensaje:"",
      index:0
    }
  }

  actualizarMensaje = (e, index)=>{
    const {value} = e.target;
    this.setState({
      ...this.state,
      mensaje:value,
      index
    })
  }

  render(){
    return(
      <Context.Provider value={{
        mensaje: this.state.mensaje,
        index: this.state.index,
        actualizarMensaje:this.actualizarMensaje
      }}>
        <div className="padre">
          <h1>EWebik - API Context</h1>
          {
            this.state.mensaje !== "" ?(
              <p className={
                this.state.index === 0 ? 'colorPadre':
                this.state.index === 1 ? 'colorHijo1':
                this.state.index === 2 ? 'colorHijo2':''
              }>{
                ((this.state.index === 0 ? 'Padre dice:':
                  this.state.index === 1 ? 'Hijo 1 dice:':
                  this.state.index === 2 ? 'Hijo 2 dice:':'')
                  + ' ' + this.state.mensaje)
              }</p>
            ):("")
          }
          <textarea
            rows="5"
            onChange={(e)=>{
              this.actualizarMensaje(e,0);
            }} />
          <div className="hijos">
            <Hijo1 />
            <Hijo2 />
          </div>
        </div>
      </Context.Provider>
    )
  }
}

ReactDOM.render(
  <Padre />,
  document.getElementById('root')
);

 

Con simplemente hacer estos cambios, nuestro aplicación funciona exactamente igual, pero ahora es más fácil de entender y leer.

Excelente, no olvides ver el vídeo donde hago todo esto paso a paso, estoy seguro que te va a gustar, no olvides en compartir este post para que llegue a mas colegas que lo necesiten, nos vemos en el siguiente post.

 


Juan Carlos G

Electrónica y diseño web

Durante años he desarrollado plataformas dedicadas al rastreo satelital y varios sitios web que se encuentran en la primera página de Google, y hoy quiero compartir contigo lo que se en tecnologías como Node JS, PHP, C# y Bases de datos, si quieres apoyarme sígueme en mis redes sociales y suscríbete a mi canal de YouTube.

Puedes seguirme en mis redes