Global State Management using React Context

Spread the love

Hello Friends, In a react application if we want to manage the state at component level, then we use useState hook for same but if you are looking for managing state at global level then react content is your answer. You may also be thinking that we can pass data using props from one component to another, but in large applications this become very complex. In this blog post we are going to look how we can store some information at global level so that all component can access that if needed and how we can also update that information.

What is React Context?

React Context is a feature in React that provides a way to share data between components without the need to pass props down manually through every level of the component tree. It allows for the creation of a global data store, which can be accessed by any component in the application. This makes it easier to manage state in large applications with complex component hierarchies. React Context consists of two main components: a context object and a provider component. The context object holds the data, and the provider component is responsible for passing the data down to the child components. The child components can then access the data using the useContext hook.

Using React Context for Global State Management

To understand how React Context can be used for global state management, let’s consider an example of a shopping cart in an e-commerce website. In a typical React application, the state of the shopping cart would be managed in the component that contains it. However, this approach can become challenging as the application grows and the shopping cart needs to be accessed by multiple components in different parts of the application.

To solve this problem, we can create a global state management solution using React Context. Here’s how it works:

Here is a new sample react app structure

React Context

1. Create a new file called “cart-context.tsx” in store directory and add below code.

import React, { useState } from "react";

interface CartContextType {
  cart: product[];
  addItem: (item: product) => void;
  removeItem: (item: product) => void;
}

const CartContext = React.createContext<CartContextType>({
  cart: [],
  addItem: (item: product) => {},
  removeItem: (item: product) => {},
});

interface product {
  id: number;
  name: string;
  quantity: number;
}

export const CartContextProvider = (props: any) => {
  const [cart, setCart] = useState(Array<product>);

  function addItem(item: product) {
    setCart([...cart, item]);
  }

  function removeItem(item: product) {
    setCart(cart.filter((i) => i.id !== item.id));
  }

  return (
    <CartContext.Provider
      value={{
        cart: cart,
        addItem: addItem,
        removeItem: removeItem,
      }}
    >
      {props.children}
    </CartContext.Provider>
  );
};

export default CartContext;

In the above code we are creating a CartContext using the React.createContext method.

The CartContextType interface defines the shape of the context value, which includes an array of product objects, and two functions for adding and removing items from the cart.

The CartContext constant creates the context with an initial value of an empty array of product objects and two empty functions.

The CartContextProvider function is a wrapper component that provides the context value to its child components. It uses the useState hook to create a state variable cart with an initial value of an empty array of product objects.

The addItem function is used to add a new product object to the cart state by spreading the existing cart array and adding the new item to the end of the array.

The removeItem function is used to remove a product object from the cart state by filtering the cart array and returning all items except the one with the matching id.

Finally, the CartContext.Provider component provides the context value to its child components by passing an object with the cart, addItem, and removeItem properties as the value prop. The child components can access this context value by using the useContext hook.

Note that the CartContextProvider function takes a props parameter but does not use it. This is because it is a wrapper component that simply provides the context value to its children and does not render any content itself.

2.Create a new component file name “add-product.tsx” in components folder and add below code.

import { useContext, useState } from "react";
import CartContext from "../store/cart-context";

function AddProduct(props: any) {
  const [productName, setProductName] = useState("");
  const [quantity, setQuantity] = useState(0);
  const cartContext = useContext(CartContext);

  const handleSubmit = (e: any) => {
    e.preventDefault();
    const id = cartContext.cart.length + 1;
    cartContext.addItem({
      id: id,
      name: productName,
      quantity: quantity,
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Product Name:
          <input
            type="text"
            value={productName}
            onChange={(e) => setProductName(e.target.value)}
          />
        </label>
      </div>
      <div>
        <label>
          Quantity:
          <input
            type="text"
            value={quantity}
            onChange={(e) => setQuantity(+e.target.value)}
          />
        </label>
      </div>

      <button type="submit">Submit</button>
    </form>
  );
}

export default AddProduct;

The above React functional component called AddProduct is responsible for rendering a form that allows the user to input the name and quantity of a product and add it to the cart.

The component imports the useContext and useState hooks from React, as well as the CartContext created in the previous code snippet.

The component defines two state variables using the useState hook: productName and quantity. These variables are used to store the user input from the form.

The component then uses the useContext hook to access the cartContext value from the CartContext component.

The handleSubmit function is called when the form is submitted. It prevents the default form submission behavior and creates a new product object with an id, name, and quantity property. The id property is generated by adding 1 to the current length of the cart array.

The cartContext.addItem function is then called with the new product object as an argument, which adds the product to the cart.

The render method returns a form with two input fields for the productName and quantity, and a submit button. The onChange event is used to update the productName and quantity state variables as the user types in the input fields.

Finally, the handleSubmit function is called when the form is submitted by the user, adding the new product object to the cart using the cartContext.addItem function.

Overall, this component provides a simple way for the user to add products to the cart by entering the name and quantity in a form. It uses the CartContext to access the cart data and the addItem function to modify it.

3.Create a new file named “list-products.tsx” in components folder and add below code.

import React, { useContext } from "react";
import CartContext from "../store/cart-context";

const ListProducts = () => {
  const { cart, removeItem } = useContext(CartContext);

  return (
    <div>
      <h2>Product List</h2>
      {cart.length === 0 ? (
        <p>Your cart is empty.</p>
      ) : (
        <ul>
          {cart.map((product) => (
            <li key={product.id}>
              {product.name} - {product.quantity}
              <button onClick={() => removeItem(product)}>Remove</button>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default ListProducts;

The above React functional component called ListProducts is responsible for rendering the list of products in the cart and allowing the user to remove products from it.

The component imports the useContext hook from React, as well as the CartContext created in the previous code snippet.

The component then uses the useContext hook to access the cart array and the removeItem function from the CartContext component.

The render method returns a div with a header and a list of products in the cart. If the cart is empty, a message is displayed indicating that it is empty. Otherwise, an unordered list is rendered with each item in the cart. For each item, the name and quantity are displayed, along with a remove button. The onClick event for the remove button calls the removeItem function with the corresponding product as an argument, removing it from the cart.

Overall, this component provides a simple way for the user to view and remove products from the cart. It uses the CartContext to access the cart data and the removeItem function to modify it.

4.Update the “App.tsx” as below.

import "./App.css";
import { CartContextProvider } from "./store/cart-context";
import AddProduct from "./components/add-product";
import ListProducts from "./components/list-products";

function App() {
  return (
    <CartContextProvider>
      <div className="App">
        <AddProduct />
        <hr />
        <ListProducts />
      </div>
    </CartContextProvider>
  );
}

export default App;

The above code is for React functional component called App that acts as the main component for the application. It renders the AddProduct and ListProducts components and wraps them in the CartContextProvider component.

The CartContextProvider component wraps the App component with the context provider, making the context and its data available to all child components.

The App component then returns a div with a class of App that contains the AddProduct and ListProducts components. The hr element is added to separate the two components visually.

Overall, this component provides the structure for the application and ensures that the context provider is available to all child components. It allows the user to add and remove products from the cart using the AddProduct and ListProducts components respectively.

Here is the working output .

Just ignore the css part for now 🙂

I have added three products and you can see that added in cart object in global context and then I am trying to remove product 2 which is also working as below. Note that we are not passing functions or data using props from one component to another component but we are using React Context to manage that cart state globally.

Conclusion

This is a introduction to React Context and how it can be used for global state management. The code snippets provided are helpful in understanding how to create and use a context object, and how to provide and access data using the useContext hook. The example of a shopping cart in an e-commerce website is a practical use case that demonstrates the benefits of using React Context for global state management.

Overall, this blog post provides a resource for anyone looking to learn about React Context and global state management in React applications.

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