How to use useReducer ?

How to use useReducer ?

Hello Everyone, In this blog we will discuss about useReducer hook in an easy way with an example. So let's get started.

What is useReducer ?

  • It is an alternative for useState.
  • useReducer is similar to useState. but useReducer is used to manage complex states. when we have multiple values to manage to maintain state, we use useReducer.
  • It takes current state, action and init function and return a new state and dispatch functions. init function here is optional.
  • It is a pure function means it returns same output for the same input.

Let us understand useReducer and how to use it.

1 . import useReducer,

import { useReducer } from "react";

2 . Consider this syntax of useReducer,

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

So, what does this syntax means here. As I said its similar to useState, useReducer also returns an array of 2 elements :

  • state : which is the current state value.
  • dispatch : It is a function which updates the value of this state. dispatch, as its name suggest it dispatches an action for the update.

We need to pass arguments here to useReducer

  • initialState : initial state value.
  • reducerFunction : which takes state and action as an input and return a updated state.

It also takes 3rd argument which is init function. which initializes initialState.

Let's implement useReducer with an example.

here we will implement a task add app in which user an can add task to personal, work and project section. clicking on the button in second section displays that particular task list.

Screenshot (1469).png

1 . lets write jsx first

<div className="App">
      <h1>Add Task</h1>

      <div>
        <input/>
        <button>Reset</button>
      </div>

      <div className="buttons">
        <button>Personal</button>
        <button>Work</button>
        <button>Project</button>
       </div> 

       <div>display Tasks</div>   

       <div className="buttons">
        <button>Personal</button>
        <button>Work</button>
        <button>Project</button>
       </div>
</div>

2 . assigning initial value for the state.

const initialState = {
    personal: [],
    work: [],
    project: [],
    displayTasks: ""
  };

three arrays and one display value holder to display desired task list.

3 . Now, to access input from user we will use useState to store input.

const [input, setInput] = useState("");

4 . Now we will write reducer function. So basically what we will do here is, we will take state and action as an input. We will also use switch case here to match case with type which is dispatched through the dispatch function. when particular action type matches we will update state else default will execute.

That means when dispatch gives 'WORK' action we will add it to work array and same for other tasks array.

const reducerFunction = (state, action) => {
    switch (action.type) {
      case "PERSONAL":
        return {
          ...state,
          personal:
            state.personal.length > 0
              ? [...state.personal, action.payload]
              : [action.payload]
        };
      case "WORK":
        return {
          ...state,
          work:
            state.work.length > 0
              ? [...state.work, action.payload]
              : [action.payload]
        };
      case "PROJECT":
        return {
          ...state,
          project:
            state.project.length > 0
              ? [...state.project, action.payload]
              : [action.payload]
        };
      case "SET_DISPLAY":
        return {
          ...state,
          displayTasks: action.payload
        };
      case "RESET":
        return action.payload;
      default:
        return state;
    }
  };

So, what is action.payload here? It is a value passed to update or modify state.

5 . now all the things are done initializing initial state and defining reducer function. Next step is to dispatch a dispatch function on an onClick event.

<button onClick={() => dispatch({ type: "PERSONAL", payload: input })}>
      Personal
</button>

dispatch takes an object of type and payload, which is responsible for input to reducer function. reducer function updates array with task in a particular category.

6 . So, the overall functions looks like this :

import { useReducer, useState } from "react";
import "./styles.css";

export default function App() {
  const [input, setInput] = useState("");
  const initialState = {
    personal: [],
    work: [],
    project: [],
    displayTasks: ""
  };

  const reducerFunction = (state, action) => {
    switch (action.type) {
      case "PERSONAL":
        return {
          ...state,
          personal:
            state.personal.length > 0
              ? [...state.personal, action.payload]
              : [action.payload]
        };
      case "WORK":
        return {
          ...state,
          work:
            state.work.length > 0
              ? [...state.work, action.payload]
              : [action.payload]
        };
      case "PROJECT":
        return {
          ...state,
          project:
            state.project.length > 0
              ? [...state.project, action.payload]
              : [action.payload]
        };
      case "SET_DISPLAY":
        return {
          ...state,
          displayTasks: action.payload
        };
      case "RESET":
        return action.payload;
      default:
        return state;
    }
  };

  const [state, dispatch] = useReducer(reducerFunction, initialState);
  return (
    <div className="App">
      <h1>Add Task</h1>
      <div>
        <input onChange={(event) => setInput(event.target.value)} />

        <button
          onClick={() => dispatch({ type: "RESET", payload: initialState })}
        >
          Reset
        </button>
      </div>
      <div className="buttons">
        <button onClick={() => dispatch({ type: "PERSONAL", payload: input })}>
          Personal
        </button>
        <button onClick={() => dispatch({ type: "WORK", payload: input })}>
          Work
        </button>
        <button onClick={() => dispatch({ type: "PROJECT", payload: input })}>
          Project
        </button>
      </div>

      <div>display Taks</div>
      <div className="buttons">
        <button
          onClick={() => dispatch({ type: "SET_DISPLAY", payload: "personal" })}
        >
          personal
        </button>
        <button
          onClick={() => dispatch({ type: "SET_DISPLAY", payload: "work" })}
        >
          Work
        </button>
        <button
          onClick={() => dispatch({ type: "SET_DISPLAY", payload: "project" })}
        >
          Project
        </button>
      </div>
      <ul>
        {state.displayTasks === "personal" &&
          state.personal.map((task, index) => <li key={index}>{task}</li>)}
        {state.displayTasks === "work" &&
          state.work.map((task, index) => <li key={index}>{task}</li>)}
        {state.displayTasks === "project" &&
          state.project.map((task, index) => <li key={index}>{task}</li>)}
      </ul>
    </div>
  );
}

Link to the above code: https://codesandbox.io/s/usereducer-example-h6csu6

7 . We can also reset state with init function here. like this

const init = (initialState) => {
  return initialState;
}

In reducerFunction

 case "RESET":
        return init(action.payload);

In this way we can use this useReducer beautifully to manage complex states.

Resources :

https://reactjs.org/docs/hooks-intro.html

I hope this blog is useful to you to understand how to use useReducer. Feel free to share your feedback in the comment section. Have a nice day beautiful people!