Introduction to Redux

Madhav GanesanMadhav Ganesan
4 min read

It is a predictable state management library for JavaScript applications, commonly used with React. It helps manage and centralize application state, making state changes predictable and easier to debug.

Redux = Context API + useReducer

Why Use Redux?

Centralized State → Stores global state in a single place (Redux store) Predictability → State changes follow strict rules, making debugging easier Easier Debugging → Tools like Redux DevTools help track state changes Better State Management → Useful in large applications with complex state interactions

Core Concepts of Redux

Store A centralized place to hold the application's state.

Actions Plain JavaScript objects that describe what should change in the state.

Reducers Pure functions that specify how the state changes based on actions.

Dispatch Sends actions to update the store.

Selectors Functions that extract and format data from the store.

  1. Store

It completely stores all the states in one place and making it easier for all the components to access any state

store.js

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

import cartReducer from './cartSlice';



const store = configureStore({

  reducer: {

    cart: cartReducer,

  },

});

export default store;
  1. Action It is a plain JavaScript object that describes what should happen in the application. Actions are sent to the reducer to update the state.
const addItem = (item) => ({
  type: 'ADD_ITEM',
  payload: item,
});
  1. Reducer
  • It is a function that determines changes to an application’s state. It uses the current state and an action to compute and return a new state.

  • It can be said like Change handler similar to Event Handler

  • It uses initial state and actions available to create a new state

  1. Slice
  • This is used to organize all the reducers for each webpage as a separate entity

  • We can add initial states and reducers along with api calls

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

const cartSlice = createSlice({

  name: 'cart',

  initialState: {

    cartProductIds: [],

  },

  reducers: {

    addToCart: (state, action) => {

      state.cartProductIds = [action.payload, ...state.cartProductIds];

    },

    removeFromCart: (state, action) => {

      const indexOfId = state.cartProductIds.indexOf(action.payload);

      if (indexOfId !== -1) {

        state.cartProductIds.splice(indexOfId, 1);

      }

    },

    clearAllItems: (state) => {

      state.cartProductIds = [];

    },

  },

});



export const { addToCart, removeFromCart, clearAllItems } = cartSlice.actions;

export default cartSlice.reducer;
  1. Provider
import React from 'react';

import ReactDOM from 'react-dom';

import { Provider } from 'react-redux';

import store from './app/store';

import App from './App';



ReactDOM.render(

  <Provider store={store}>

    <App />

  </Provider>,

  document.getElementById('root')

);

Hooks required for redux

1) useSelector

This is used to extract particular state from redux store

const selectedData = useSelector((state) => state.someData);

2) useDispatch

This is used to send off actions to the redux store

// src/features/cart/CartComponent.js

import React from 'react';

import { useSelector, useDispatch } from 'react-redux';

import { addToCart, removeFromCart, clearAllItems } from './cartSlice';



const CartComponent = () => {

  const cartProductIds = useSelector((state) => state.cart.cartProductIds);

  const dispatch = useDispatch();



  return (

    <div>

      <h1>Cart</h1>

      <ul>

        {cartProductIds.map((id) => (

          <li key={id}>

            Product ID: {id}

            <button onClick={() => dispatch(removeFromCart(id))}>Remove</button>

          </li>

        ))}

      </ul>

      <button onClick={() => dispatch(clearAllItems())}>Clear All</button>

      <button onClick={() => dispatch(addToCart(123))}>Add Product 123</button>

    </div>

  );

};



export default CartComponent;

Redux Thunk

It is a middleware that allows you to write asynchronous logic (like API calls) inside Redux actions. It enables action creators to return functions instead of plain objects.

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

// Define an async thunk to fetch data
export const fetchUser = createAsyncThunk(
  'user/fetchUser',
  async (userId) => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
    return response.json();
  }
);

const userSlice = createSlice({
  name: 'user',
  initialState: { data: null, loading: false, error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => { 
        state.loading = true; 
      })
      .addCase(fetchUser.fulfilled, (state, action) => { 
        state.loading = false;
        state.data = action.payload; 
      })
      .addCase(fetchUser.rejected, (state, action) => { 
        state.loading = false;
        state.error = action.error.message; 
      });
  }
});

export default userSlice.reducer;

Redux Toolkit (RTK)

It is the official, recommended way to write Redux logic. It simplifies state management by reducing boilerplate code, improving performance, and making Redux easier to use.

Stay Connected! If you enjoyed this post, don’t forget to follow me on social media for more updates and insights:

Twitter: madhavganesan

Instagram: madhavganesan

LinkedIn: madhavganesan

0
Subscribe to my newsletter

Read articles from Madhav Ganesan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Madhav Ganesan
Madhav Ganesan

I am a computer science student passionate about web development and any other technologies that amazes me