DEV Community

Cover image for Let's Learn Redux (Complete Tutorial)
Sagar Kattel
Sagar Kattel

Posted on

Let's Learn Redux (Complete Tutorial)

Basically when you are starting out your career in React development field, you must have stumble upon the concept of Redux. And it might seem tedious and so much boilercode that it can even demotivate you on your journey. But i am here to rescue you to learn those concept in breeze and in simple language as well so hold your horses as i embark you on the journey to completely learn Redux.

So let's start with its definition:

Redux is a very popular JavaScript library that is designed to manage the state of data in JavaScript applications

Also you must have stumble upon the work state of data but what does the state of data refers?
It simply means :

A state in Redux is a JavaScript object, where the internal state of the application is stored as its properties

This definition also seems kind of vague representation for you guys but let me explain it to you using simple words using an working example as it can help you wrap around the concept more easily.

When we login into an website, we get the login detail and we might want to pass that details to different pages within the website. We can't fetch the login details in every page as fetching Api's can be quite expensive. In the practical scenario we fetch the Api once and keep its data somewhere in the client side and send the data in every page.

Generally there are two ways to store data and to pass on that data to every page i.e

  • Use useContext hook

  • Use Redux hook

useContext hooks works on the principle of prop drilling. It means it passes the data based on the hierarchy. In computer terminology, data is passed from the parent component to its child component which also refers to top-down approach. Here in this approach we fetch the data from the Api once then we pass the data to the useContext page and we put the useContext hook in the top level of the application then the data can be accessed in every page subsequent to its child page. Simple enough right? If you are stuck here i will do deep dive related to it in another article. Also i will show you how to implement it in our application. Our sole focus today is to make you understand about Redux concept.

Redux on the other hand is another hook that also works on the principle of prop drilling. It consits of 3 parts i.e

  1. Store

  2. Reducers

  3. Dispatch and Selector

The Redux store is the main, central bucket which stores all the states of an application. It should be considered and maintained as a single source of truth for the state of the application.
If the store is provided to the App.js (by wrapping the App component within the <Provider> </Provider> tag) as shown in the code snippet below, then all its children (children components of App.js) can also access the state of the application from the store. This makes it act as a global state.

Let's create an application to even understand it further with its implementation detail. Here for our simplicity, we take an example of Ecommerce Cart System.

At first Create Provider for the store in our application. This will ensure that the data from the store are drilled down at the top level i.e index page and it's subsequent page i.e App page can access the data. App contains further collection of pages.


// src/index.ts

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'

import { App } from './App'
import createStore from './createReduxStore'

import { store } from "./store";

// As of React 18
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <Provider store={store}>
    <App />
  </Provider>
Enter fullscreen mode Exit fullscreen mode

Meanwhile create store that manages the application along with the Reducers and dispatch and selector function. Store consists of configureStore function to initialize the reducers along with setupListeners functions. Also we initialize the dispatch function in the name of AppDispatch and export it.

//store.ts


import { configureStore } from '@reduxjs/toolkit';

import productSlice from './features/productSlice';

export const store = configureStore({
    reducer: {
      product:productSlice,
    }
  })

  setupListeners(store.dispatch);


  // Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
Enter fullscreen mode Exit fullscreen mode

Now let's create productSlice feature for our react application which is also known as Reducers here in redux concept.


//productSlice.ts

import { createSlice, PayloadAction } from "@reduxjs/toolkit";

export interface ProductProp {
  id: number;
  title: string;
  img_url: string;
  price: number;
  rating: number;
  quantity: number;
}

interface ProductState {
  products: ProductProp[];
}

const initialState: ProductState = {
  products: [],
};

export const productSlice = createSlice({
  name: "product",
  initialState,
  reducers: {
    addProduct: (state, action) => {
      const product = action.payload;

      // Check if a product with the same ID already exists in the state.products array
      const existingProductIndex = state.products.findIndex(
        (existingProduct) => existingProduct.id === product.id
      );
      if (existingProductIndex !== -1) {
        console.log("Product Already Exists");
        state.products[existingProductIndex].quantity += 1;
      } else {
        // If no product with the same ID exists, add the product to the array
        state.products.push({ ...product, quantity: 1 });
      }
    },
    removeProduct: (state, action) => {
      const productload = action.payload;
      state.products = state.products.filter(
        (product) => product.id !== productload
      );
    },
  },
});

export const { addProduct, removeProduct } = productSlice.actions;

export default productSlice.reducer;

Enter fullscreen mode Exit fullscreen mode

This is it now you have successfully configured the store along with the actions. Now all you have to do is call useDispatch and useSelector to perform the actions. Let's take a peek to how can we achieve it

//Card.tsx

import { useAppDispatch, useAppSelector } from "@/redux/hooks";
import { addProduct } from "@/redux/features/productSlice";


const dispatch=useAppDispatch();

const Card=()=>{

const [productsList, setProducts] = React.useState([]);


  const handleClick=(product:productT)=>{
    dispatch(addProduct(product))
    console.log(product)
  }


return(
<div>
 {products.map((product)=>(

<div key={product.id}>
<button onClick={()=>handleClick(product)}> Add to Cart </button>
</div>
))}

</div>
);
}

export default Card;

Enter fullscreen mode Exit fullscreen mode

Here using useAppDispatch, we call the function addProduct reducers to perform the actions and pass value into it.

//Cart.tsx

import { useAppDispatch, useAppSelector } from "@/redux/hooks";
import { ProductProp, removeProduct } from "@/redux/features/productSlice";


const Cart=()=>{

const dispatch=useAppDispatch();

const products:ProductProp[] = useAppSelector((state:any) => state.product.products);


return(
<div>
 {products.map((product)=>(

<div key={product.id}>

<button onClick={(event) => dispatch(removeProduct(product.id))}>Remove</button>
</div>
))}

</div>
);
}

export default Cart;


Enter fullscreen mode Exit fullscreen mode

Here we first view the products that we obtain from the the the store using useAppSelector as it helps to view the data stored in store in the name products and map it out then we perform the necessary dispatch to modify the data in the store with the help of reducers.

This is the perfect representation of the application of Redux. I hope this gives you in-depth understanding on this subject matter of Redux.

Sayonara😉! (The word sayonara means "goodbye" or "farewell.")

Top comments (0)