Introduction

When managing complex states in React, useState often falls short. This is where useReducer comes in, providing a more structured way to handle state transitions.

In this article, we’ll explain useReducer, provide TypeScript-based examples to ensure type safety and clarity and discuss its benefits.


What is useReducer?

useReducer is a React Hook that provides an alternative to useState. It is useful for predictably handling state logic, especially in complex scenarios where multiple state updates depend on each other.

Syntax:

const [state, dispatch] = useReducer(reducer, initialState);
  • state: The current state value.

  • dispatch: A function used to trigger state changes.

  • reducer: A function that takes the current state and an action, then returns a new state.

  • initialState: The default state when the component mounts.


Why Use useReducer Instead of useState?

  • Better state management: Suitable for complex state logic with multiple transitions.

  • Predictability: State transitions are centralized in a reducer function.

  • Improved debugging: Actions make state changes more traceable.


Implementing useReducer in TypeScript

Let’s implement a simple counter with useReducer.

Step 1: Define State and Actions

type State = {
  count: number;
};

type Action = { type: "INCREMENT" } | { type: "DECREMENT" } | { type: "RESET" };

Step 2: Create the Reducer Function

const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + 1 };
    case "DECREMENT":
      return { count: state.count - 1 };
    case "RESET":
      return { count: 0 };
    default:
      return state;
  }
};

Step 3: Use useReducer in a Component

import { useReducer } from "react";

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <h2>Count: {state.count}h2>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Incrementbutton>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>Decrementbutton>
      <button onClick={() => dispatch({ type: "RESET" })}>Resetbutton>
    div>
  );
};

export default Counter;

Handling Complex State

When dealing with more complex states, useReducer scales better than useState. For example, managing a form’s state:

Define State and Actions

type FormState = {
  username: string;
  email: string;
};

type FormAction =
  | { type: "CHANGE_USERNAME"; payload: string }
  | { type: "CHANGE_EMAIL"; payload: string }
  | { type: "RESET" };

Create the Reducer Function

const formReducer = (state: FormState, action: FormAction): FormState => {
  switch (action.type) {
    case "CHANGE_USERNAME":
      return { ...state, username: action.payload };
    case "CHANGE_EMAIL":
      return { ...state, email: action.payload };
    case "RESET":
      return { username: "", email: "" };
    default:
      return state;
  }
};

Use in a Component

const Form = () => {
  const [state, dispatch] = useReducer(formReducer, { username: "", email: "" });

  return (
    <div>
      <input
        type="text"
        value={state.username}
        onChange={(e) => dispatch({ type: "CHANGE_USERNAME", payload: e.target.value })}
        placeholder="Username"
      />
      <input
        type="email"
        value={state.email}
        onChange={(e) => dispatch({ type: "CHANGE_EMAIL", payload: e.target.value })}
        placeholder="Email"
      />
      <button onClick={() => dispatch({ type: "RESET" })}>Resetbutton>
      <p>Username: {state.username}p>
      <p>Email: {state.email}p>
    div>
  );
};

export default Form;

When Should You Use useReducer?

  • When state logic is complex and interdependent.

  • When the next state depends on the previous one.

  • When you need more predictable state transitions.

  • When managing state in large-scale applications.


Conclusion

useReducer is a powerful alternative to useState, especially for managing complex state logic.

Using it with TypeScript enhances type safety and maintainability. By structuring state updates through actions and a reducer function, useReducer makes React applications more scalable and predictable.


🌐 Connect With Me On:

📍 LinkedIn
📍 X (Twitter)
📍 Telegram
📍 Instagram

Happy Coding!