Twitter LogoFacebook Logo
useReducer Hook
Learn what is the useReducer Hook and why use it
By: King

The purpose of useReducer hook is similar to the useState hook. Both are used for updating the state of some value.

One major advantage of using the useReducer hook is, as the name suggests, to reduce the amount of code in a single callback function by dividing different actions using different functions.

For useState, we create one like this:

let [ state, setState ] = useState(0);

The variable and mutator function is extracted by deconstructing the useState object. And the default value is passed as an argument.

For useReducer, it is similar:

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

1. state represents the current state managed by the reducer

2. dispatch is a function used to dispatch actions to update the state

3. reducer is a function that receives the current state and an action, and returns the new state based on the action

4. initialState is the starting value for the state

Let's see how this works.

Using useReducer

Step 1:

Import useReducer from React

import { useReducer } from "react";

Step 2:

Create the useReducer

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

Step 3:

Create the reducer function (the name can be anything, we're just using "reducer" here)

function reducer(state, action) {
    return state;
}

Note that the reducer function should have 2 parameters.

1. state represents the current value of the useReducer
2. action is an arbritary name for the parameter that contains the object that is passed when calling dispatch.

Step 4:

Set the initial value to an arbitrary string value.

function reducer(state, action) {

    return state;
}
let [statedispatch] = useReducer(reducer, "Codeible");

Step 5:

Add a button with a onClick event and use interpolation to insert the value of the value of the useReducer.

function App() {
  function reducer(state, action) {
    return state;
  }
  const [state, dispatch] = useReducer(reducer, "Codeible");

  return (
    <div>
      <button
        onClick={() => {

        }}>
        {state}
      </button>
    </div>
  );
}

export default App;

You should get this:

Image from Codeible.com

Step 6:

Update the useReducer state by calling dispatch and passing in "WelcomeMessage" in the onClick event function.

onClick={() => {
   dispatch("WelcomeMessage");
}}

Now when we click on the button, the value of the action parameter in the reducer function should be "WelcomeMessage"

Add a console.log state in the reducer function and print out the value of action.

  function reducer(state, action) {
    console.log(action);
    return state;
  }

If we click on the button, we should see "WelcomeMessage" printed on the console.

Image from Codeible.com

The idea is to use the action as an identifier to determine what we want to do with the state. So in the reducer function, we can either use the IF or Switch statement. Normally it is better with the Switch.

Step 7:

Use the switch statement with the action argument to determine the case.

function reducer(state, action) {
    switch(action){
      case "WelcomeMessage":
        break;
    }
    return state;
}

Step 8:

Set the value of state to "Hello World" in the case of "WelcomeMessage"

switch(action){
      case "WelcomeMessage":
        state = "Hello World"
        break;
}

Now when we click on the button, the text of the button should change.

Image from Codeible.com

Having Multiple Actions

As you saw in the first exercise, we passed an "action" into the reducer function and use it to determine what we want to do with the state.

However, that example has only 1 case and it does not really show you the power of using useReducer.

So to make it more clearer -

Step 1:

Add 2 more buttons call "Print Name" and "Print Age" with a onClick event assigned to them. Then call dispatch with "name" and "age" respectively.

<button onClick={() => { dispatch("WelcomeMessage"); }}>{state}</button>
<button onClick={() => { dispatch("name"); }}>Print Name</button>
<button onClick={() => { dispatch("age"); }}>Print Age</button>

Step 2:

Add the name and age to the case

switch(action){
      case "WelcomeMessage":
        state = "Hello World"
        break;
      case "name":

        break;
      case "age":

        break;
}

Step 3:

Set state to your name when the case is "name" and when the case is "age," set it to your age:

switch(action){
      case "WelcomeMessage":
        state = "Hello World"
        break;
      case "name":
        state = "King"
        break;
      case "age":
        state = "20"
        break;
}

Now when you click on each button, the text of the original button will change.

Image from Codeible.com

As you can see, by using setReducer, we can specify what we want to do with the state for a specifc situation.

But this is a very simple case. Normally, instead of adding logic inside the case, we should create a function for each case so it "reduces" the amount of code in the reducer function.

function function_for_WelcomeMessage(state) {
    // Do something with state and return it.
    return state;
}
function function_for_name(state) {
    // Do something with state and return it.
    return state;
}
function function_for_age(state) {
    // Do something with state and return it.
    return state;
}

function reducer(state, action) {
    switch (action) {
      case "WelcomeMessage":
        state = function_for_WelcomeMessage(state);
        break;
      case "name":
        state = function_for_name(state);
        break;
      case "age":
        state = function_for_age(state);
        break;
    }
    return state;
}

That's all for setReducer. By using this concept, we successfully "reduce" the amount of code in the reducer function.


Sign In