¿Cómo utilizar el Hook useReducer?

¿Cómo utilizar el Hook useReducer?
Juan Carlos G2020-10-13

Hola viajero, hemos avanzado muy bien en este curso de React JS, hoy toca hablar del Hook useReducer, el cual, estoy seguro te será muy útil en tus proyectos, como siempre veremos su declaración, definición y mucho más, espero te guste este post.

Si te esta gustando este curso, puedes ayudarme compartiendo este post, suscribiéndote a mi boletín y a mi canal.

 

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

 

¿Qué aprenderás de useReducer?

  • Cómo declararlo.
  • La forma correcta en que debes inicializar tu state.
  • Aprenderás a crear tu función reducer.
  • Haremos un ejemplo donde mediante un clic incrementaremos o disminuiremos el valor de un contador.

 

 

Repositorio

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

 

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

El Hook useReducer es un Hook que nos permite manipular el state de nuestros componentes funcionales, esto se logra a través de:

  • Una función reducer
  • Y un función de retorno llamada dispatch con la cual podemos combinar o emparejar el state.

UseReducer esta basado en la librería Redux, es por ello que, aparecen las palabras, reducer y dispatch.

 

¿Cuándo usar el Hook useReducer?

Bien, esto no será una respuesta como tal, ya que, depende del tipo de proyecto, pero, se pueden tomar como recomendaciones para tomar una decisión:

  • Cuando el estado siguiente del "state" depende del estado anterior.
  • Cuando manejas un objeto JSON como state y tienes subvalores dentro de tu mismo objeto.
  • Cuando la lógica es muy compleja.

 

 Declaración de useReducer

En forma general podemos declarar a este Hook de la siguiente forma.

const [state, dispatch] = useReducer(reducer, initialArg, init);

No obstante, la declaración también depende de como decidamos iniciar el state:

  • Podemos especificar el estado inicial.
  • O podemos especificar un estado inicial en forma diferida.

 

Especificando el estado inicial de useReducer

La forma más sencilla de inicializar el state es, especificar el objeto del state y pasarlo como segundo parámetro al useReducer, tal y como lo hacemos en el vídeo.

const [state, dispatch] = useReducer(reducer,initialState);

 

Inicialización del state en forma diferida

Esto no lo ocupamos en el vídeo, pero, no esta de más que conozcas esta opción. Esta forma hace referencia que, usamos todos los argumentos de useReducer, donde:

  • El primero no cambia, será nuestra función reducer.
  • El segundo sigue siendo valores iniciales que tendrá nuestro state, sin embargo, no será el valor inicial total de nuestro state.
  • El tercer parámetro es una función que recibirá el objeto del segundo argumento, aquí construiremos nuestro state final y lo regresaremos.

Creo que debo explicar un poco más ese tercer argumento, simplemente debemos entender que, esta función recibirá como argumento el objeto que se encuentra en el segundo argumento de useReducer, y dentro de esta función, puedes decidir como tomar este dato y agregarlo al state final, esto quiere decir que, puedes tener este objeto más otros datos que requieras agregar al state, por ejemplo:

function init(initState) {
  return {
      ...initState,
      dato:true
  };
}

function Counter({initState}) {
    const [state, dispatch] = useReducer(reducer, initState, init);
   
   ....

}

Si deseas que haga un ejemplo de esto en vídeo, suscríbete a mi canal y déjame un mensaje en los comentarios de este vídeo, si hay muchos comentarios hago un ejemplo de esto.

 

¿Cómo utilizar useReducer?

Bien, espero que en este punto ya hayas visto el vídeo de la clase, donde, hacemos un ejemplo paso a paso y te explico cada parte del código y, obviamente, ya esta el código en el repositorio.

Creo que lo que falta nada más es establecer un par de ventajas y desventajas al utilizar este Hook.

 

Ventajas

  • Permite actualizar el state a partir de un estado anterior.
  • La lógica de la actualización de subatributos de nuestro state, es más fácil de comprender.

Desventajas

  • De entrada, debes escribir mucho más código que si utilizarás useState.
  • Debes de aprender nuevos conceptos, como lo es el: reducer y dispatch.

 

Excelente, aquí te dejo el resumen del vídeo y el ejemplo que desarrollamos, pero, te recomiendo que cuando tengas tiempo mires el vídeo para que despejes cualquier duda.

 

Ejemplo contador

El ejemplo que vamos hacer es un pequeño contador que tiene la capacidad de:

  • Contará con un checkbox que indicará si la cuenta aumenta o disminuye.
  • UN input text que indicará el intervalo de la cuenta
  • Un botón que aumente la cuenta o la disminuya, según el valor del checkbox
  • Otro botón que realice un reset y regrese al contado a su estado inicial.

Ejemplo del contador utilizando useReducer

Como puedes observar es una interfaz muy simple, pero, ten en cuenta que lo que estamos estudiando es al Hook y no estilos, así que, para fines demostrativos nos sirve perfectamente.

 

State Inicial

Lo primero que vamos hacer es declarar nuestro state inicial, es recomendable que este objeto o JSON, este declarado fuera de tu componente, a menos que venga en las propiedades claro.

//Estado inicial
const initialState = {
  count:0,
  countInterval:1,
  increment:true
}

 

Declaración del reducer

Ahora vamos a crear la función reducer donde actualizaremos el valor del state

//Reducer, el cual debe cumplir con las características de una función pura
const reducer = (state, action)=>{
  switch (action.type) {
    case "INCREMENT":
      return{
        ...state,
        increment: action.increment
      }
    case "SET_INTERVAL":
      return{
        ...state,
        countInterval: parseInt(action.countInterval)
      }
    case "INCREASE_COUNT":
      return{
        ...state,
        count: state.count + state.countInterval
      }
    case "DECREASE_COUNT":
      return{
        ...state,
        count: state.count - state.countInterval
      }
    case "RESTART":
      return initialState;
    default:
      //Lanzar un error
      return state;
  }
}

La función reducer por lo regular es un swith donde evalúas el valor de TYPE, esta función debe contar con las características de una función pura:

  • Una función pura en JavaScript se refiere a que dadas ciertas entradas, regresará siempre las mismas salidas.
  • Un función pura, no afecta ni modifica los atributos de entrada.

 

Declaración de nuestro componente

const Counter = ()=>{
  //Declaración
  //const [state, dispatch] = useReducer(()=>{},{});
  const [state, dispatch] = useReducer(reducer,initialState);

  const handleIncrement = (e)=>{
    const {checked}=e.target;
    dispatch({type:"INCREMENT",increment:checked});
  }
  const handleCountInterval = (e)=>{
    const {value}=e.target;
    dispatch({type:"SET_INTERVAL",countInterval:value});
  }
  const handleCount = (e)=>{
    if(state.increment){
      dispatch({type:"INCREASE_COUNT"});
    }else{
      dispatch({type:"DECREASE_COUNT"});
    }
  }
  const handleRestart = (e)=>{
    dispatch({type:"RESTART"});
  }

  return(
    <div className="padre">
      <h1>{"Hook useReducer by EWebik"}</h1>
      <p>{"Cuenta: " + state.count}</p>
      <div>
        <input
          type="checkbox"
          id="chk"
          checked={state.increment}
          onChange={handleIncrement} />
        <label htmlFor="chk">
          {"Incrementar"}
        </label>
      </div>
      <br/>
      <div>
        <label htmlFor="interval">
          {"Intervalo"}
        </label>
        <input
          type="text"
          id="interval"
          value={state.countInterval}
          onChange={handleCountInterval} />
      </div>
      <br/>
      <button onClick={handleCount}>
        {state.increment ? "Incrementar":"Decrementar"}
      </button>
      <button onClick={handleRestart}>
        {"Reiniciar"}
      </button>
    </div>
  )
}

 

Utilización del dispatch

Como pudiste observar, en los manejadores de eventos utilizamos el dispatch, ya que, a través del llamado de esta función, le pasamos los parámetros a la función reducer para que esta actualice el state.

  • En el dispatch debemos pasar el atributo a evaluar en el swith que en este caso es el TYPE más los demás a tributos que deseamos actualizar en el state, por ejemplo:
const handleIncrement = (e)=>{
    const {checked}=e.target;
    dispatch({type:"INCREMENT",increment:checked});
  }

 

  • No obstante, en el dispatch podemos pasar únicamente el atributo a evaluar (TYPE), por ejemplo:
  const handleCount = (e)=>{
    if(state.increment){
      dispatch({type:"INCREASE_COUNT"});
    }else{
      dispatch({type:"DECREASE_COUNT"});
    }
  }

 

Y listo, ya tenemos nuestro contador funcionando a través de useReducer, si bien, lo pudimos hacer utilizando useState, es un excelente ejemplo de como puedes utilizar cada uno de los argumentos de este Hook.

 


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