Table of contents
1.
Introduction
2.
Redux Data Flow
3.
Data Fetching in Redux
4.
Redux-Thunk Middleware
5.
Frequently Asked Questions
5.1.
What is the difference between synchronous and asynchronous logic?
5.2.
What is Redux middleware?
5.3.
Where is Redux middleware used?
5.4.
What is the convention for data fetching in Redux?
5.5.
What is Redux-Thunk, and why is it used?
6.
Conclusion
Last Updated: Mar 27, 2024
Hard

Async Logic and Data Fetching in Redux

Author dhananjay
1 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Redux is a state management library that centralizes the application's data. Redux is an open-source javascript library that can be integrated with most frameworks. We can manage the application's data globally, making our data flow more efficient than the general approach.
 

introduction image

In this blog, we will learn how to fetch the data in Redux, and we will also learn how to fetch the data asynchronously in Redux. We will use a react app to implement the data fetching with Redux.

Also See, Dropdown in React JS

Redux Data Flow

Before we implement the data fetching, let's first understand how data flows in the Redux application. 

Assuming that you know the terms used in Redux, for example, action, dispatch, reducers, and many more. Check out the Redux basic concept blog if you need help understanding these terms or brush up on your knowledge.

Let's see the data flow in the redux application.

redux data flow

In the UI, users will trigger an event to initiate pre-defined actions. Let’s say we need the detail of a particular product from the various products. We are currently on the all-product page.

Now to get the detail of a particular product, we will click on the specific product, which will result in triggering the event. First, we will trigger the dispatcher, who will recognize the type of action and initiate that particular action from the predefined actions.

After starting the action, we will pass it on to the reducer, who updates the state according to the action we are initiating. In this case, our action is to get the detail of a particular product.

The reducer function will update the state in the store, and the store will pass on the updated state to the UI, and the user will see the product detail on the screen.

Data Fetching in Redux

Now we have understood the data flow in Redux, let's see how to fetch the data in Redux.

As mentioned above, we will use the react app as a frontend to display the data using Redux.

Our project will fetch the data from a public Application Programming Interface( API), giving us random cat facts. We will display the random cat facts on the browser.

Create react project in the root folder.

npx create-react-app project-name


We need to install some more dependencies to create the react-redux project.

npm i react
npm i react-redux
npm i axios


Let me show you our project's folder structure.

project folder structure

Now we have all the required dependencies to create our project.

First, we will create an action type for our project. Since it is a small project, we need only one action type.

fact.js

export const setfact = (fact) => {
    return {
        type: 'SET_FACTS',
        payload: fact
    }
}
You can also try this code with Online Javascript Compiler
Run Code


We have declared the setfact function, which will return the action type and payload. Payload is the javascript object which contains the current state of data.

Now we will create the reducer for the action we have created.

increment.js

const intialstate = {
    fact: []
}

const reducerfunction = (state = intialstate, action) => {
    if (action.type === "SET_FACTS") {
        return {
            ...state,
            fact: action.payload
        };
    }
    return state
}

export default reducerfunction;
You can also try this code with Online Javascript Compiler
Run Code


We need to declare an initial state for our reducer function. In the reducerfunction, we will take two arguments state, and the second is action. If the action type is equal to the mentioned action type, ‘SET_FACTS’, it will return the updated state in this case.

We have created our action and reducer. We need to set up our store to manage the state or data in the application.

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {createStore} from 'redux.'
import { Provider } from 'react-redux';
import reducerfunction from './reducer/increment';
let store = createStore(reducerfunction)

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
 <Provider store={store}>
        <App />
 </Provider>

);
You can also try this code with Online Javascript Compiler
Run Code


We need to import the createStore from Redux and Provider from react-redux. We will initialize the store variable with the createStore() method and set the reducerfunction as the argument.

Now we will add the functionality in our app.js file to fetch the data from the https://catfact.ninja/fact endpoint using the Axios and display it on the screen while updating the state with the help of Redux.

const catdata = async () => {
    const res = await axios.get('https://catfact.ninja/fact')
        .catch(error => {
            console.log(error)
        })
    console.log(res)
}
You can also try this code with Online Javascript Compiler
Run Code


We have used async/await keywords in the above code to apply the asynchronous logic. Making an API call is asynchronous because the program has to wait until we get a response from the API.

An async function returns a promise as the output. We must use await keyword in the async because it holds the execution of the program until the promise is resolved or rejected. In the above code, we are applying the await before axios.get() request which will hold the execution until we get a response from the API. 

App.js

import { useSelector, useDispatch } from 'react-redux';
import axios from 'axios';
import { useEffect } from 'react';
import { setfact } from './actions/fact';

function App() {

const factstate = useSelector(state => state)
const dispatch = useDispatch()
  const{fact} = factstate

  const catdata = async () =>{
   const res = await axios.get('https://catfact.ninja/fact')
    .catch(error => {
      console.log(error)
    })
    console.log(res.data.fact)
    dispatch(setfact(res.data.fact))
  }

useEffect(()=>{
   catdata()
},[])

  return (
    <div>
      <h1>Random Cat Facts</h1>
      {fact && <p>{fact}</p>}
      <button onClick={catdata}>More Facts</button>
    </div>
 
  );
}
export default App;


In the above file, we will create a button that will call the catdata function. The catdata function will get the response from the API, and we will send this API data to the dispatch method to initiate the SET_FACTS action.

Once the action is initiated, we call the reducerfunction to update the application's state. We will take care of the state using the useSelector method. We will display the state as  {fact && <p>{fact}</p>} in the file.

Now write the “npm start” in the terminal to run the application. You will see a random cat fact on the screen.

output1

If you click on more facts, it will change the fact automatically.

output2

This is how we can fetch the data in Redux.

But what if we want to implement the data fetching asynchronous in the Redux store? You must know you cannot implement the async data fetching inside the Redux. The example we have implemented is fetching the data asynchronously outside the Redux store.

We need middleware to implement the asynchronous data fetching in the Redux store.

Redux-Thunk Middleware

By default, Redux follows the synchronous logic for the data flow. So we cannot simply involve the API calling in the Redux store.

To add asynchronous logic, we need the redux-thunk middleware. Another reason to use Redux thunk is that it returns the functions instead of plain javascript objects. We can apply the async logic or request in the returned function called the thunk function and hold the redux synchronous data flow.

Redux-thunk reduces redundancy because we can use these action creators as a service. We do not need to again apply the GET request or other requests in other components. With Redux-thunk, API requests can be centralized. We need to call the dispatcher for that particular request.

 

redux thunk data flow

The above picture shows the middleware, a redux-thunk middleware between the action and reducer. The middleware will be initiated; when the user dispatches the action, and then the middleware will use the API and halt the redux data flow until we get the response.

Then the response from the middleware will be transferred to the reducer in the redux store to update the current state and then update the UI depending on the response from API.


First, we need to install the middleware in our react-redux project.

npm i redux-thunk


Now, we need to import the applyMiddleware from the Redux library and thunk from the Redux-thunk library to use this middleware. We will pass on the applyMiddleware as the second argument in our store and thunk as the parameter of applyMiddleware.

let store = createStore(reducerfunction,applyMiddleware(thunk))
You can also try this code with Online Javascript Compiler
Run Code


index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {createStore,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux';
import reducerfunction from './reducer/increment';

let store = createStore(reducerfunction,applyMiddleware(thunk))

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
 <Provider store={store}>
        <App />
 </Provider>

);
You can also try this code with Online Javascript Compiler
Run Code


Now, in our first project, we were fetching the data inside our app.js file. Now we will transfer that functionality to our action creator, SET_FACTS.

fact.js

import axios from "axios"
export const setfact = () => async (dispatch) => {
    const res = await axios.get('https://catfact.ninja/fact')
    dispatch({
        type: 'SET_FACTS',
        payload: res.data.fact
    })
}
You can also try this code with Online Javascript Compiler
Run Code


In the above function, we can see the implementation of the redux-thunk middleware. The above function can be called a thunk function. We can see the arrow function calls another async arrow function which will fetch the data from the endpoint and send it to the reducer function to update the state according to the action type.

Here the redux execution will be held until we get the response from the API we have called in the function, and then we can again dispatch the action to call the reducer.

increment.js

const intialstate = {
    fact: []
}

const reducerfunction = (state = intialstate, action) => {
    if (action.type === "SET_FACTS") {
        return {
            ...state,
            fact: action.payload
        };
    }
    return state
}

export default reducerfunction;
You can also try this code with Online Javascript Compiler
Run Code


Above is our reducer function.

App.js

import { useSelector, useDispatch } from 'react-redux';
import { useEffect } from 'react';
import { setfact } from './actions/fact';

function App() {
const factstate = useSelector(state => state)
const dispatch = useDispatch()
  const{fact} = factstate

  const catdata = () =>{
    dispatch(setfact())
  }

useEffect(()=>{
   catdata()
},[])

  return (
    <div>
      <h1>Random Cat Facts</h1>
      {fact && <p>{fact}</p>}
      <button onClick={catdata}>More Facts</button>
    </div>
 
  );
}

export default App;
You can also try this code with Online Javascript Compiler
Run Code


Output

thunk output

If you click on more facts, it will change the fact automatically.

thunk output

Frequently Asked Questions

What is the difference between synchronous and asynchronous logic?

Digital sequential logic circuits can either be synchronous or asynchronous in kind. Synchronous sequential circuits change the device state only at discrete times in response to a clock signal. Asynchronous circuits, however, change the state at any time in response to changing inputs.

What is Redux middleware?

Redux middleware is a code snippet providing a third-party extension between dispatching actions and when they reach the reducers. All middleware has next() to call the following action in the queue. It extends Redux with custom functionality.

Where is Redux middleware used?

Redux middleware is often used for logging, crashing reports, talking to some asynchronous API, routing, etc. It provides a third-party extension between dispatching actions and when they reach the reducers.

What is the convention for data fetching in Redux?

For data fetching, Redux actions generally come in triplets as BEGIN, SUCCESS, and FAILURE. Before starting the API call, the BEGIN action is dispatched. On succeeding, SUCCESS is dispatched with the data.

What is Redux-Thunk, and why is it used?

Redux Thunk middleware allows users to return functions instead of just actions. This will permit delayed actions and is primarily used to handle actions that may be asynchronous.

Conclusion

In this blog, we have discussed the data flow of the Redux application. We have also learned to fetch data from an API in the Redux application. We have also discussed and implemented the Redux-thunk middleware to fetch the data asynchronously.

To learn more about Redux, check out the following articles.

To learn more about DSA, competitive coding, and many more knowledgeable topics, please look into the guided paths on Coding Ninjas Studio. Also, you can enroll in our courses and check out the mock test and problems available to you. Please check out our interview experiences and interview bundle for placement preparations.

Happy Coding!

Live masterclass