React Fundamentals

0% completed

Previous
Next
Understanding the useReducer Hook

We've seen how states work and its importance in building React applications that are dynamic and maintainable. While the useState hook is often sufficient for simple state management, complex state logic calls for a more structured approach. This is where the useReducer hook comes in. It is a powerful alternative that simplifies complex state transitions in functional components.

What is the useReducer hook

The useReducer hook is a state management tool in React that allows you manage state logic by using a reducer function. The useReducer helps you transition state from one form to another in response to dispatched actions.

Syntax

The useReducer is written in this pattern:

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

Here we have:

  • state: The current state being managed.
  • dispatch: A function used to send actions to the reducer.
  • reducer: A function that defines how state transitions occur. It takes the current state and an action as arguments and returns the new state.
  • initialState: The initial value of the state.
Image

Example

Let's look at a simple counter example to understand how the useReducer works. The entire process would be broken down into steps for you to grasp it better.

Step One: Define the Reducer Function

A reducer function takes two parameters: the current state and the action. Based on the action type, it returns the updated state.

const counterReducer = (state, action) => { switch (action.type) { case "increment": return { count: state.count + 1 }; case "decrement": return { count: state.count - 1 }; case "reset": return { count: 0 }; default: throw new Error(`Unknown action: ${action.type}`); } };

In this reducer function:

  • Two parameters are taken, which are:

    • state: The current state object (typically with a count property).
    • action: An object that describes the action to be performed (with a type property).
  • A switch statement is used to determine which action to process based on the action.type

  • In the switch statement, we have the following cases:

    • Case "increment": If the action type is "increment", the state is updated by increasing the count value by 1 and returns an object with the updated count: { count: state.count + 1 }.
    • Case "decrement": If the action type is "decrement", the state is updated by decreasing the count value by 1 and returns an object with the updated count: { count: state.count - 1 }.
    • Case "reset": If the action type is "reset", the state is reset to 0 and returns an object with count set to 0: { count: 0 }.
    • Default case: If the action type doesn't match any of the defined cases ("increment", "decrement" or "reset"), an error is thrown. The error message includes the unknown action type: Unknown action: ${action.type}.

The main purpose of this reducer function is to update the count value in the state based on specific actions like increment, decrement, and reset.

Step Two: Initialize State with useReducer

After creating our reducer function, we now initialize the state using the useReducer hook.

import React, { useReducer } from "react"; export default function Counter(){ const initialState = { count: 0 }; const [state, dispatch] = useReducer(counterReducer, initialState); return ( <div> <h1>Count: {state.count}</h1> <button onClick={() => dispatch({ type: "increment" })}>Increment</button> <button onClick={() => dispatch({ type: "decrement" })}>Decrement</button> <button onClick={() => dispatch({ type: "reset" })}>Reset</button> </div> ); };

In this code example:

  • We import the useReducer hook from React.
  • An initial state object is defined with a count property, starting at 0.
  • The useReducer hook is called with:
    • counterReducer: the reducer we created, which would handle state changes based on actions.
    • initialState: The initial state for the counter ({ count: 0 }).
  • The useReducer returns an array of state and dispatch.
  • The Counter component returns JSX which contains; a <h1> element displaying the current count value (state.count) and three <button> elements, each with an onClick event handler that dispatches different actions

These buttons are:

  • Increment: Dispatches an action with type: "increment" to increase the count.
  • Decrement: Dispatches an action with type: "decrement" to decrease the count.
  • Reset: Dispatches an action with type: "reset" to reset the count to 0.

Output

Having successfully created our Counter component with its reducer function using the useReducer hook, here is how it displays on the browser:

Image
Counter component using useReducer

How does the useReducer compare to useState

The hooks share common similarities such as:

  • They both involve a current state value.
  • They both have a function that triggers a state update.
  • They both have an initial state value passed as an argument.

Why use useReducer Over useState?

While useState is excellent for simple state management, useReducer is best suited in scenarios like:

  • Complex State Logic: When the state relies on multiple variables or transitions that depend on prior states.
  • Predictable State Updates: Using a reducer makes state updates predictable and easier to debug.
  • Action-Based Updates: You need a centralized mechanism to handle state transitions based on actions.

.....

.....

.....

Like the course? Get enrolled and start learning!
Previous
Next