Let's Learn Redux (Complete Tutorial)
Tags: javascript, programming, react, opensource
Published: 2023-11-02 17:49:59

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>
```

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
```
 
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;

```

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;

```

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;


```

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.")