DEV Community

Cover image for Introduction to Redux
Madhav Ganesan
Madhav Ganesan

Posted on

Introduction to Redux

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;
Enter fullscreen mode Exit fullscreen mode

2) 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,
});

Enter fullscreen mode Exit fullscreen mode

3) 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

4) 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;
Enter fullscreen mode Exit fullscreen mode

5) 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')

);
Enter fullscreen mode Exit fullscreen mode

Hooks required for redux

1) useSelector

This is used to extract particular state from redux store

const selectedData = useSelector((state) => state.someData);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)