Redux and Redux Toolkit(RTK)

January 2, 2025 (4w ago)

Web-developement

INTRODUCTION

Redux is a predictable state container for javascript applications. It manages and stores application states in a more structured and maintainable way, its predictability property comes with merits like keeping track of your states in the state container. For this to be possible a pattern is enforced to ensure all the state transitions are explicit based on the action dispatched and can be tracked.

In Redux, the state represents the entire state of your application. It is a single JavaScript object that holds the data your application needs. The state object is stored in the Redux store, which is responsible for managing the state and updating it when actions are dispatched. ln other words the state of an app is the state that is shared by all of the individual components of that app.

The state in Redux is immutable, meaning that it cannot be modified directly. Instead, when an action is dispatched, a new state object is created based on the previous state and the action. This new state object replaces the previous state in the store. This approach makes it easier to track changes in the state and enables features like time-travel debugging.

installation of redux to your project,run this command in your project directory

npm init
npm i redux
const redux = require('redux');

This is used in a Node.js environment to import the Redux library. It uses the CommonJS module system to import the Redux library and assign it to a constant variable named redux. Once you have the Redux library imported, you can access its functions and methods to create and manage your application's state.

ACTIONS

The only way your application can interact with the store in order to update the state of your application, you need to let redux know about that with an action, not allowed to directly update the state object. Generally, actions carry some information from your application to the store, these actions are plain javascript objects.

Each action has a type property, which is a string that describes the action's purpose. Optionally, actions can also have a payload property, which contains any additional data needed to update the state.

Creating Actions in Redux

To create actions in Redux, follow these steps:

Define Action Types

Action types are constants that represent the different actions that can be dispatched to update the state. They are usually defined as string constants to avoid typos and make it easier to manage the actions.

const FETCH_USER_REQUESTED = 'FETCH_USER_REQUESTED';
const FETCH_USER_SUCCESS = 'FETCH_USER_SUCCESS';
const FETCH_USER_FAILED = 'FETCH_USER_FAILED';

Create Action Creators

Action creators are functions that return action objects. These objects have a type property, which corresponds to an action type, and an optional payload property, which contains any additional data needed to update the state.

// fetchUserRequested: This action creator is called when the user fetching process starts.
const fetchUserRequested = () => {
    return {
        type: FETCH_USER_REQUESTED
    };
};
 
// fetchUserSuccess: This action creator is called when the user fetching process is successful.
const fetchUserSuccess = (users) => {
    return {
        type: FETCH_USER_SUCCESS,
        payload: users
    };
};
 
// fetchUserFailed: This action creator is called when the user fetching process fails.
const fetchUserFailed = (error) => {
    return {
        type: FETCH_USER_FAILED,
        payload: error
    };
};

Reducers

Reducers specify how the application's state changes in response to actions sent to the store.

Reducers are pure functions that accept state and action as arguments and return the new state of the application.

Define the Initial State

The initial state is an object that represents the default state of your application.

const initialState = {
    loading: false,
    user: [],
    error: ''
};

Define the Reducer Function

The reducer function takes the initial state and an action as arguments and returns a new state based on the action type and payload.

const reducer = (state = initialState, action) => {
    switch (action.type) {
        case FETCH_USER_REQUESTED:
            return {
                ...state,
                loading: true
            };
        case FETCH_USER_SUCCESS:
            return {
                loading: false,
                user: action.payload,
                error: ''
            };
        case FETCH_USER_FAILED:
            return {
                loading: false,
                user: [],
                error: action.payload
            };
        default:
            return state;
    }
};

Store

In Redux, the store holds your application's state. You can access your state via getState(), and update it by dispatching actions.

The subscribe method allows you to listen for changes in the store. It takes a callback function as an argument, which will be called whenever the state changes. The subscribe method returns an unsubscribe function that can be called to stop listening for updates.

unsubscribe(); // Stops listening for state updates.

Thunk Action Creator

The fetchUsers function is a thunk action creator that returns a function taking dispatch as an argument. Inside this function, you dispatch the fetchUserRequested action, make an API call using Axios, and then dispatch either fetchUserSuccess or fetchUserFailed based on the API result.

const fetchUsers = () => {
    return function(dispatch) {
        dispatch(fetchUserRequested());
        axios.get('https://jsonplaceholder.typicode.com/users')
            .then(response => {
                const users = response.data.map(user => user.id);
                dispatch(fetchUserSuccess(users));
            })
            .catch(error => {
                dispatch(fetchUserFailed(error.message));
            });
    };
};

Create the Redux Store with Thunk Middleware

To use Redux Thunk for handling asynchronous actions, apply the middleware when creating the store.

const redux = require('redux');
const thunkMiddleware = require('redux-thunk').default;
const axios = require('axios');
const applyMiddleware = redux.applyMiddleware;
 
// Create the store
const store = redux.createStore(reducer, applyMiddleware(thunkMiddleware));
store.subscribe(() => { console.log(store.getState()); });
store.dispatch(fetchUsers);

Here, you create the Redux store using createStore, passing in your reducer and applying thunkMiddleware using applyMiddleware. The subscription logs state changes to the console whenever the state updates. Finally, you dispatch the fetchUsers thunk action, which triggers the API call and updates the store's state accordingly.

Redux Toolkit(RTK)

Web-developement

Redux Toolkit is an opinionated, batteries-included toolset for efficient Redux development. It is recommended to be the standard way to write Redux logic, and we strongly recommend that you use it.

Redux toolkit is referred to as "opinionated" because it provides a set of recommended practices, convections, and utility functions that encourage a specific way of structuring and organizing redux code.

Redux toolkit is also considered "batteries-included" because it comes with built-in utilities. These built-in features help developers with reduced amount of boiler-plate code they need to write and this helps them to get started quickly.

installation of the redux toolkit to your project, run this command in your project directory

npm install @reduxjs/toolkit

CREATESLICE

Createslice is a function that generates a slice of the redux store, including the reducer, function action creators, and current state.

therefore it helps to reduce boilerplate code and makes it easier to define a redux store.

In redux, we write case reducer functions inside the reducer objects and give them readable names. However, with create slice in the toolkit will automatically generate action creators that correspond to each case reducer function we have and it automatically returns the existing state as the default state.

Createslice allows us to safely "mutate "our state ,it utilises a library called immer inside. Immer uses a special javascript tool called proxy to swap data you provide and lets you write code that mutate although Immer tracks all the changes you've tried to make and then uses that list of changes to return a safely immutably updated value.

import { createSlice } from "@reduxjs/toolkit";
import  { SliderData }from '../../assests/data/chunkData'
 
export const sliderSlice = createSlice({
    name:'slider',
    initialState:{
        value: 0,
        length:SliderData.length,
    },
    reducers:{
        leftSlide(state,action){
            state.value = action.payload < state.length -1 ? 0 : action.payload
        },
        rightSlide(state,action){
            state.value = action.payload > state.length -1 ? 0 : action.payload
        },
        dotSlide(state,action){
            const slide = action.payload
            state.value = slide
        }
 
 
    }
})
 
export const {leftSlide,rightSlide,dotSlide} =sliderSlice.actions
export default sliderSlice.reducer
 

Explanation:

This code defines a Redux slice for managing the state of a slider component. It provides actions for moving the slider left, right, or directly to a specific dot, and the reducer updates the state accordingly.

CONFIGURE STORE

configureStore is a utility function provided by Redux Toolkit that simplifies the process of setting up a Redux store. It automatically applies a set of recommended middleware, configures the Redux DevTools extension, and combines the provided reducers.

That one call to configure the store does all the work for us like instead of combined when we have more than one reducer.

import { configureStore } from '@reduxjs/toolkit';
import slideReducer from '../features/slices/sliderSlice';
import itemReducer from '../features/slices/itemSlice'
import cartReducer from '../features/slices/cartSlice'
 
 
export const store = configureStore({
  reducer: {
    slider: slideReducer,
    item: itemReducer,
    cart:cartReducer
  },
});

Explanation:

In summary, this code configures the Redux store by combining multiple reducers from different slices into a single store using Redux Toolkit's configureStore function.

createAsyncThunk

createAsyncThunk is a utility function provided by Redux Toolkit that simplifies the process of handling asynchronous actions in Redux. It generates a set of action creators and action types for a given async operation, and automatically dispatches the appropriate actions based on the operation's state.

import { createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
 
export const fetchUsers = createAsyncThunk(
  'users/fetch',
  async (_, { dispatch, rejectWithValue }) => {
    try {
      dispatch(fetchUserRequested());
      const response = await axios.get('https://jsonplaceholder.typicode.com/users');
      const users = response.data.map((user) => user.id);
      return users;
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);
 

Explanation:

By regenerating the fetchUsers function using createAsyncThunk, you can handle the asynchronous fetching of users and handle success and failure scenarios in a more streamlined and standardized way using Redux Toolkit.