Using React Redux for Global State Management

Spread the love

Hello Friends, In a react application if you want to manage global state then you can use useState hook and pass them using props to components or React context for same. The another way to manage global state is React Redux which is a popular library for state management in react. Lets us understand about this and see how we can use React Redux in our React applications for centalized state managemment.

What is React Redux?

React Redux is a state management library for React applications. It is based on the Redux library and provides a way to manage the state of an application in a predictable and centralized manner.In React Redux, the state of an application is stored in a single store object. The store is the single source of truth for the entire application and can be accessed from any component in the application.React Redux also provides a set of helper functions and components to make it easier to connect React components to the store and to dispatch actions that modify the state of the application.Using React Redux can help improve the performance and scalability of React applications by minimizing the amount of state that needs to be passed down through component props, and by providing a predictable way to manage the state of the application as it grows and evolves.

Getting Started with React Redux

Let us start with React Redux by creating a new project with typescript using below command

npx create-react-app react-redux-tutorial --template typescript

To get started with React Redux, we need to install the necessary packages.

We can do this using npm by running the following command in the above application.

npm install @reduxjs/toolkit react-redux

Then, Create files and directories as per below structure.

Add below code in types.tsx file

export interface Item {
  id: number;
  name: string;
  price: number;
}
export interface CartState {
  cartItems: Item[];
}

export interface Action {
  type: string; 
  payload: Item;
}

The above TypeScript interfaces that define the shape of two objects: Item and CartState, as well as an Action interface for defining actions in Redux.

The Item interface specifies that an object of this type should have three properties: id, name, and price. id is a number, name is a string, and price is a number.

The CartState interface specifies that an object of this type should have one property: cartItems. cartItems is an array of objects that conform to the Item interface.

The Action interface specifies that an object of this type should have two properties: type and payload. type is a string that describes the action being performed, while payload is an object that contains the data associated with the action. In this case, payload is an object that conforms to the Item interface.

Add below code in actions.tsx

import { Item } from "./types";
export const addToCart = (item: Item) => {
  return {
    type: "ADD_TO_CART",
    payload: item,
  };
};

export const removeFromCart = (item: Item) => {
  return {
    type: "REMOVE_FROM_CART",
    payload: item,
  };
};

These are two functions that define actions in a Redux application. They import the Item interface from the types.ts file.

The addToCart function takes an Item object as a parameter and returns an object with two properties: type and payload. The type property is a string that describes the action being performed, in this case, “ADD_TO_CART”. The payload property contains the Item object passed to the function.

The removeFromCart function also takes an Item object as a parameter and returns an object with two properties: type and payload. The type property is a string that describes the action being performed, in this case, “REMOVE_FROM_CART”. The payload property contains the Item object passed to the function.

These functions are designed to be used with a Redux store, which manages the state of the application. The addToCart and removeFromCart functions can be dispatched to the store and processed by reducers to update the application state accordingly.

Add below code in store.tsx

import { AnyAction, configureStore, Reducer } from "@reduxjs/toolkit";
import { CartState, Action } from "./types";

const initialState: CartState = {
  cartItems: [],
};

export const cartReducer: Reducer<CartState, Action | AnyAction> = (
  state = initialState,
  action
) => {
  switch (action.type) {
    case "ADD_TO_CART":
      const result = {
        ...state,
        cartItems: [...state.cartItems, action.payload],
      };
      console.log("result", result);
      return result;
    case "REMOVE_FROM_CART":
      return {
        ...state,
        cartItems: state.cartItems.filter(
          (item) => item.id !== action.payload.id
        ),
      };
    default:
      return state;
  }
};

export const store = configureStore({
  reducer: cartReducer,
});

The abvove code exports a cartReducer and a store object using Redux Toolkit.

The initialState object defines the initial state of the CartState object as an empty array for the cartItems property.

The cartReducer function is a Redux reducer that takes two parameters: state and action. The state parameter is set to the initialState object by default. The action parameter is the action dispatched to the store.

The reducer function uses a switch statement to handle different types of actions. If the action type is “ADD_TO_CART”, it creates a new state object by copying the original state using the spread operator and appending the new item to the cartItems array. If the action type is “REMOVE_FROM_CART”, it returns a new state object with the cartItems array filtered to remove the item with the same ID as the payload item. If the action type is not recognized, it returns the original state object.

The store object is created using the configureStore function from Redux Toolkit. It takes an object with a reducer property, which is set to the cartReducer function defined above. This creates a store with the cartReducer as the sole reducer.

Add below code in AddProduct.tsx

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { addToCart } from "../store/actions";
import { Item } from "../store/types";

interface AddProductProps {
  products: Item[];
}

export function AddProduct(props: AddProductProps) {
  const { products } = props;
  const [name, setName] = useState("");
  const [price, setPrice] = useState("");
  const dispatch = useDispatch();

  function handleNameChange(e: React.ChangeEvent<HTMLInputElement>) {
    setName(e.target.value);
  }

  function handlePriceChange(e: React.ChangeEvent<HTMLInputElement>) {
    setPrice(e.target.value);
  }

  function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    let id = 1;
    if (products) {
      id = products.length + 1;
    }
    const item = { id, name, price: Number(price) };
    dispatch(addToCart(item));
    setName("");
    setPrice("");
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Product Name"
        value={name}
        onChange={handleNameChange}
      />
      <input
        type="number"
        placeholder="Price"
        value={price}
        onChange={handlePriceChange}
      />
      <button type="submit">Add Product</button>
    </form>
  );
}

This is a React component that allows users to add new products to the Redux store by dispatching the addToCart action. The component imports the addToCart action from the Redux store, as well as the Item interface from the types file.

The component takes a single prop called products, which is an array of Item objects.

The component uses the useState hook to manage the state of the name and price inputs. It also uses the useDispatch hook from the react-redux library to get access to the Redux store dispatch function.

The handleNameChange and handlePriceChange functions update the name and price state variables respectively whenever the corresponding input changes.

The handleSubmit function is called when the form is submitted. It prevents the default form submission behavior, creates a new Item object with the name and price state variables, and dispatches the addToCart action with this Item object as the payload. It also resets the name and price state variables to empty strings.

The return statement renders a form with two input fields for name and price, as well as a submit button. When the user enters values in the input fields and clicks the submit button, the handleSubmit function is called, which dispatches the addToCart action to add the new product to the store.

Add Below code in ListProducts.tsx

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { removeFromCart } from "../store/actions";
import { Item } from "../store/types";

interface ListProductsProps {
  products: Item[];
}

export function ListProducts(props: ListProductsProps) {
  const { products } = props;
  const dispatch = useDispatch();
  return (
    <ul>
      {products?.length === 0 && <li>No products in cart</li>}

      {products?.map((product) => (
        <li key={product.id}>
          {product.name} - ${product.price}
          <button onClick={() => dispatch(removeFromCart(product))}>
            Remove
          </button>
        </li>
      ))}
    </ul>
  );
}

This is a React component that displays a list of products from the Redux store and allows users to remove products from the store by dispatching the removeFromCart action. The component imports the removeFromCart action from the Redux store, as well as the Item interface from the types file.

The component takes a single prop called products, which is an array of Item objects.

The component uses the useSelector and useDispatch hooks from the react-redux library to get access to the cartItems array from the Redux store and the dispatch function respectively.

The return statement renders an unordered list (ul) of products by mapping over the products prop array and rendering a list item (li) for each product. Each list item displays the product name and price, as well as a remove button that dispatches the removeFromCart action with the corresponding Item object as the payload when clicked.

If the products array is empty, the component renders a single list item that says “No products in cart”.

Overall, this component allows users to view the products in their cart and remove them if needed.

Add below code in ShoppingCart.tsx

import React from "react";
import { useSelector } from "react-redux";
import { CartState } from "../store/types";
import { AddProduct } from "./AddProduct";
import { ListProducts } from "./ListProducts";

export function ShoppingCart() {
  const cartItems = useSelector((state: CartState) => {
    return state.cartItems;
  });
  const totalPrice = cartItems?.reduce((total, item) => total + item.price, 0);
  return (
    <div>
      <AddProduct products={cartItems} />
      <ListProducts products={cartItems} />
      <p>Total: ${totalPrice?.toFixed(2)}</p>
    </div>
  );
}

This is a React component that displays the shopping cart. The component imports the useSelector hook from react-redux, the CartState interface from the types file, and two child components called AddProduct and ListProducts.

The component uses the useSelector hook to get access to the cartItems array from the Redux store. The cartItems array is then passed as a prop to the AddProduct and ListProducts child components.

The component also calculates the total price of all items in the cart using the reduce method on the cartItems array. The total price is then rendered as a paragraph (p) element.

The return statement renders the AddProduct and ListProducts child components, as well as the total price of the items in the cart.

Overall, this component allows users to view and interact with their shopping cart, including adding new products and removing existing ones. The total price of all items in the cart is also displayed for easy reference.

Update App.tsx file with below code.

import React from "react";
import "./App.css";
import { ShoppingCart } from "./components/ShoppingCart";

function App() {
  return (
    <div className="App">
      <ShoppingCart />
    </div>
  );
}

export default App;

The above code will render ShoppingCart component which will further render AddProduct and ListProduct comoponents. Tt will displays a list of products and a form to add new products to the cart. You can also remove products from the cart and the total price will be automatically updated.

Now lets run the react application. Here is the output

Lets add few products and see if we are getting updated list or not. Here is the screen after adding four products with different prices.

Lets try to remove any product, let us choose “Product3” and check if the list is further updated or not. Here is the screen after removing “Product3” from store by clicking “Remove” button.

Its seems like everthing is working fine.

Summary

The blog post introduces React Redux as a state management library for React applications. React Redux is based on the Redux library and allows developers to manage the state of an application in a centralized and predictable way. The post explains how to get started with React Redux by creating a new project, installing necessary packages, and creating files and directories for the project. It defines TypeScript interfaces to define the shape of objects and actions in Redux, such as Item, CartState, and Action interfaces. It also explains the functions that define actions in a Redux application, such as addToCart and removeFromCart functions. Additionally, it describes the cartReducer function, which is a Redux reducer that takes two parameters, state and action. Finally, the blog post explains the store object, which is created using the configureStore method and the cartReducer function. The post provides a simple example of how to add items to and remove items from the cart using React Redux. You can further read about React Redux here.

Thanks and Happy Learning :). Please give your valuable feedback and share this post if you liked and learned something from this post.

Leave a Comment