Open In App

What is the use of useReducer ?

Last Updated : 09 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

useReducer is a tool in React that helps manage the state in a more organized way. It’s like a central hub where you can handle different changes to your state based on various actions. One example use case for ‘useReducer‘ in React is managing a shopping cart state. You can use ‘useReducer’ to handle actions like adding items to the cart, removing items, and updating quantities. This helps simplify complex state logic and keeps related code organized in one place, improving the maintainability and scalability of your application.

Prerequisites

Steps to Create the React Application

Step 1: Create a React application using the following command:

npx create-react-app foldername

Step 2: After creating your project folder i.e. foldername, move to it using the following command:

cd foldername

Step 3: After setting up react environment on your system, we can start by creating an App.js file and create a file by the name of components in which we will write our desired function.

Project Structure

Screenshot-2024-03-05-182124

The updated dependencies in package.json file will look like:

"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Approach

  • First define the Reducer Function this is basically a regular JavaScript function that takes two parameters
    • state: This represents the current state of our application.
    • action: This is an object that describes the type of action we want to perform and optionally carries additional data with it (payload).
  • Inside the reducer function, we typically use a switch statement to handle different types of actions that can occur in our application. These actions are represented by strings (action types) and describes how the state should be updated.
  • After handling all possible action types, we return the new state object. It’s crucial to always return a new state object and never modify the existing state directly.
  • Finally, we include a default case in our switch statement to handle any action types that are not explicitly defined. In most cases, this default case simply returns the current state without making any changes.

Example 1: Let’s consider a simple shopping cart application. The state of the shopping cart might include an array of items, each with properties like name, quantity, and price. Users can add items to the cart, remove items, or update the quantity of items.

CSS
/* index.css */

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}

h1 {
  font-size: 3.2em;
  line-height: 1.1;
}

button {
  border-radius: 8px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1em;
  font-weight: 500;
  font-family: inherit;
  background-color: #1a1a1a;
  cursor: pointer;
  transition: border-color 0.25s;
}

button:hover {
  border-color: #646cff;
}

button:focus,
button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }

  button {
    background-color: #f9f9f9;
  }
}
Javascript
//App.js

import React, { useReducer } from 'react'
import './styles.css'

// Define reducer function
const cartReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return {
        ...state,
        items: [...state.items, action.payload]
      }
    case 'REMOVE_ITEM':
      return {
        ...state,
        items: state.items.filter(
          (item) => item.id !== action.payload.id
        )
      }
    case 'CLEAR_CART':
      return {
        ...state,
        items: []
      }
    default:
      return state
  }
}

const App = () => {
  // Initial state for the shopping cart
  const initialState = {
    items: []
  }

  // useReducer hook to manage state
  const [cartState, dispatch] = useReducer(cartReducer, initialState)

  // Function to add item to cart
  const addItemToCart = (item) => {
    dispatch({ type: 'ADD_ITEM', payload: item })
  }

  // Function to remove item from cart
  const removeItemFromCart = (item) => {
    dispatch({ type: 'REMOVE_ITEM', payload: item })
  }

  // Function to clear the cart
  const clearCart = () => {
    dispatch({ type: 'CLEAR_CART' })
  }

  return (
    <div className="shopping-cart">
      <h2>Shopping Cart</h2>
      <ul className="product-list">
        {cartState.items.map((item) => (
          <li key={item.id} className="product-item">
            {item.name} - Rs {item.price}
            <button className='removeBtn' 
                    onClick={() => removeItemFromCart(item)}>
              Remove
            </button>
          </li>
        ))}
      </ul>
      <button onClick={clearCart}>Clear Cart</button>
      <hr />
      {/* Product list */}
      <h2>Available Products</h2>
      <ul className="product-list">
        <li className="product-item">
          <button
            onClick={() =>
              addItemToCart({
                id: 1,
                name: 'Product 1',
                price: 10
              })
            }
          >
            Add Product 1 to Cart
          </button>
        </li>
        <li className="product-item">
          <button
            onClick={() =>
              addItemToCart({
                id: 2,
                name: 'Product 2',
                price: 20
              })
            }
          >
            Add Product 2 to Cart
          </button>
        </li>
        <li className="product-item">
          <button
            onClick={() =>
              addItemToCart({
                id: 3,
                name: 'Product 3',
                price: 30
              })
            }
          >
            Add Product 3 to Cart
          </button>
        </li>
      </ul>
    </div>
  )
}

export default App

Output:

frt

Example 2: Let’s consider another example i.e. a task management application where users can create, edit, and delete tasks. Each task has properties like title, description, and status (e.g., “pending” and “completed”).

CSS
/* App.css */

.container {
    max-width: 600px;
    margin: 0 auto;
    padding: 20px;
    font-family: Arial, sans-serif;
}

h1 {
    text-align: center;
}

.task-list {
    list-style: none;
    padding: 0;
}

.task-item {
    background-color: #f9f9f9;
    border: 1px solid #ddd;
    margin-bottom: 10px;
    padding: 15px;
}

.task-item h2 {
    margin-top: 0;
}

.task-item p {
    margin: 10px 0;
}

.button-container {
    display: flex;
    justify-content: flex-end;
}

.complete-button,
.delete-button,
.add-button {
    padding: 8px 16px;
    margin-left: 10px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

.complete-button {
    background-color: #5cb85c;
    color: #fff;
}

.delete-button {
    background-color: #d9534f;
    color: #fff;
}

.add-button {
    background-color: #337ab7;
    color: #fff;
}

.complete-button:hover,
.delete-button:hover,
.add-button:hover {
    background-color: #4cae4c;
}

.add-button:hover {
    background-color: #286090;
}
JavaScript
// App.js

import React, { useReducer } from 'react';
import './App.css';

// Reducer function
const taskReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TASK':
      return {
        ...state,
        tasks: [...state.tasks, action.payload]
      };
    case 'UPDATE_TASK':
      return {
        ...state,
        tasks: state.tasks.map(task =>
          task.id === action.payload.id ? 
              { ...task, ...action.payload.updates } : task
        )
      };
    case 'DELETE_TASK':
      return {
        ...state,
        tasks: state.tasks.filter(
            task => task.id !== action.payload)
      };
    default:
      return state;
  }
};

const App = () => {
  // Initial state
  const initialState = {
    tasks: []
  };

  // useReducer hook
  const [state, dispatch] = 
      useReducer(taskReducer, initialState);

  const addTask = task => {
    dispatch({ type: 'ADD_TASK', payload: task });
  };

  const updateTask = (taskId, updates) => {
    dispatch({ type: 'UPDATE_TASK', payload: { id: taskId, updates } });
  };

  const deleteTask = taskId => {
    dispatch({ type: 'DELETE_TASK', payload: taskId });
  };

  return (
    <div className="container">
      <h1>Task Manager</h1>
      <ul className="task-list">
        {state.tasks.map((task, index) => (
          <li key={task.id} className="task-item">
            <div>
              <h2>{`${index + 1}. ${task.title}`}</h2>
              <p>{task.description}</p>
              <p>Status: {task.status}</p>
              <div className="button-container">
                <button
                  onClick={
                      () => updateTask(task.id, { status: 'completed' })}
                  className="complete-button">
                  Complete
                </button>
                <button onClick={
                    () => deleteTask(task.id)} className="delete-button">
                  Delete
                </button>
              </div>
            </div>
          </li>
        ))}
      </ul>
      <button
        onClick={() =>
          addTask({
            id: Date.now(),
            title: `Task ${state.tasks.length + 1}`,
            description: '',
            status: 'pending'
          })
        }
        className="add-button">
        Add Task
      </button>
    </div>
  );
};

export default App;

Output:

usereducer2

Steps to run the Application:

Type the following command in the terminal:

npm start

Type the following URL in the browser if the browser doesn’t opens automatically:

 http://localhost:3000/

UseCases for useReducer

  • Shopping Cart: Manage adding, removing, and updating items in a shopping cart.
  • Authentication: Handle login/logout actions and user info updates.
  • Forms: Manage form state, input changes, submission, and validation.
  • Wizard Steps: Control multi-step processes or wizards in an application.
  • Real-Time Updates: Handle state changes in response to real-time data updates.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads