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.