Redux - A state management tool

Photo by Windows on Unsplash

Redux - A state management tool

In this blog, we will learn about the different state management tools and we will learn why we need to use a state management tool when we build a large-scale application.

We have different state management tools such as Redux, Zustand and many more.

Why do we need to use Redux as a State Management Tool?

Initially, we will learn why there is a need to use ReduxJs as a global state management tool while we have useState Hook to store all the variables data.

  1. As we already know useState can only be used in the component.

  2. To pass the data from one component to another component, we can do in 3 ways :

    1. Props

    2. Context and

    3. State Management Tool(Redux, Recoil etc.). We will see each of them in detail and when to use them.

  3. If we want to update and maintain data across the application in different components(independent of each other) we need to use a state management tool that acts as a central store where every component can access the data. Let's Learn about Redux now!

What is Redux?

Redux is a state management tool that can be used with any JavaScript framework like Angular, VueJs and ReactJS(It's a library). In simple terms, Redux is a state container that helps you to write JavaScript apps across Client, server and Mobile apps. Redux is a read-only container, whenever we have to update the data in the state, we can do it by dispatching an action. Dispatching an action means which describes what changes we want to make in the state.

Redux can be installed from the redux toolkit into the react application.

npm install react-redux @reactjs/toolkit

Redux is divided into 3 things: State, Action and Reducer.

Core-Principles of Redux?

Store - The store acts like a central place for the application which holds all the data for the application. We can have only one store for each application to make the logic easier.

Three important points to remember while creating a store:

  1. A store is an object.

  2. The only we can change the data inside of a store is to dispatch an action.

  3. We should always pass the root reducer to the store.

Let's see how we can create a store:

import { createStore } from 'redux';
import { rootReducer } from 'reducers/rootReducer'
const appStore = createStore(rootReducer);
export default appStore;

createStore() - It is used to create a store object

getState() - It is used to access the state inside the store.

dispatch() - It is used to dispatch an action(i.e.,changing the data/value of a state).

Action - Action can be simply defined as a callback function with payload as an argument and it should return an object along with the type which is further passed to the reducer.

Let's see how we can create an action:

const ADD = "ADD";
const EDIT = "EDIT";

const addTodo = () => {
  return { type:ADD }
}

const editTodo = () => {
  return { type:EDIT }
}

export {ADD,addTodo, EDIT, editTodo };

Reducer - Reducers are pure functions that contain the logic and calculations that need to be performed on the state.

These functions accept the initial state of the state being used and the action type. It updates the state and responds with the new state

Let's see how we can create a reducer:

const initialState = 0;

const rootReducer = (state = initialState, action) => {
  switch(action.type){
     case 'ADD':
      let newTodo = {
        id: action.todo.id;
        todo: action.todo.todo;
      }
     return  state.concat([newTodo]);

   default:
     return state;
   }
}

In reducer, we manage the state data. First, we initialize the initial state and a root reducer function.

The root reducer function takes the initial state and the action to update the state changes.

Selector - A selector is a pure function that takes a state object from the Redux store and returns some information extracted from that state object.

Selectors can be used to provide the data from redux to react components.

Let's see how we can create a basic selector:

export const getTodo = ({ todo }) => todo;

Why do we need to use selectors to pass the data to the component?

Following are a few reasons to use selectors:

  1. Selectors are efficient because selectors are not recomputed unless they change their argument data.

  2. Selectors can compute derived data and it allows the redux to store the minimal data.

How to pass the data from redux to the Component Level?

We will use the combineReducers method from redux to combine all the required reducers for the app.

For example, we have two reducers such as AddTodo and EditTodo.Let's see how we can combine these reducers.

//create an index.js file
import { combineReducer } from 'redux';
//import the required reducers
import { reducer1 } from './reducer1';
import { reducer2 } from './reducer2';

export const combineReducers({
 reducer1,
 reducer2
})

The next step is to set up redux store configurations with the configureStore() method which returns the store by using the createStore() method with the arguments as initialState, reducer and middlewares.

The final step is to pass a returned store to the app component.

import React from 'react';
import { Provider } from 'react-redux';
//import the configureStore method and assign to the stor variable

export default function App(){
   return(
      <Provider store={store}>
       <p>This is a todo component</p>
      </Provider>
     )
}

What is Redux Middleware?

First, we will know what is middleware.

Generally, middleware is software that sits between the operating system and the application. Essentially it is used as a communication medium to transfer data.

While building web interfaces, we use middleware to communicate/transfer the data between the component layer and the redux layer.

Types of redux middleware?

We have two types of middleware which are provided by redux. Redux-thunk and Redux-saga.

First, we will know what is thunk and saga and later we will implement with a sample react app.

What is Redux-thunk?

Whenever we want to create a function for an action, it allows us to write synchronous code. If we have a scenario to include complex operations in an action and there is a need to write an asynchronous code, Here we can use redux-thunk.

Generally, a thunk means a piece of code that does some delay work. In Redux, thunks are for creating an async function with some logic to interact with store dispatch methods.

Why do we use redux-thunk?

We can include logic in the component by using useEffect, but as for best practices for developing react applications, we have to keep the presentation layer and logic separately. This is the reason we use redux-thunks to write complex logic.

Basic steps to include redux-thunk in the react app:

npm install redux-thunk

A simple example for creating an action with thunk:

const INCREMENT = 'INCREMENT';

function increment(){
   return {
     type: INCREMENT
  } 
}

function incrementAsync(){
   return dispatch => {
     setTimeout(() => {
       dispatch(increment())
     }, 1000)
   }
}

What is Redux-Saga?

The scenario to use redux-saga is very similar to redux-thunk. Redux-saga is implemented as software because we can't use reducers directly to coordinate and trigger asynchronous data fetching.

Why do we use redux-saga?

Using redux-saga it makes easier to test the state variables. As frontend developer, we have to manage how the data flows from the backend to the frontend, i.e., to manage the shared states across react components and we should not repeat the data fetching multiple times.

npm i redux-saga

Why do we use redux-saga when we have redux-thunk already available?

In redux-saga, it becomes very easy to write functions and test them effectively. But in redux-thunk, it becomes hard to test

In redux-saga, we create a saga directory to keep our saga code separate and we write generator functions for triggering asynchronous operations. We are doing this because the data has to be passed through the middleware and then to the reducer.

Implement Redux-Saga in your React TypeScript Project. | by Moatez Bejaoui  | eDonec | Medium

Difference between redux-thunk and redux-saga?

There is no right answer to this. But we have a few scenarios for this:

  1. Redux-thunk is beginner-friendly.

  2. Redux-thunk can become quite complex when we are working with large volumes of data.

  3. In the case of data-fetching operations, redux-saga functions will be easier to test effectively while redux-thunk is harder to test.

What are props and ContextAPI? When to use Props, ContextAPI and Redux?

Props are simple ways to pass the data from one component to another component. If we have to change the prop, we have to change it from the parent component. With props, we can pass the data to the child components from the parent component.

Context API is used when we have to pass the data in all the components without passing props to every component.

Redux can be used whenever we need to pass the required data to a specific component.

Conclusion:

  1. ReduxJS can be used for larger projects.

  2. ReduxJS can be categorized into 3 things: Action, Reducers and Store.

  3. Each React app can have only one store to make things simpler.

  4. Redux has 2 middlewares: Redux-thunk and Redux-Saga

In the upcoming articles, I will write up on in-detail implementations of creating a simple todoApp with ReduxThunk and ReduxSaga.

References:

Redux-toolkit

Thunk as a Middleware

Saga as a Middleware

Did you find this article valuable?

Support Swarupa Rani by becoming a sponsor. Any amount is appreciated!