Author avatar

Gaurav Singhal

Redux Strategy with Async Data and Interaction

Gaurav Singhal

  • Aug 27, 2020
  • 6 Min read
  • Aug 27, 2020
  • 6 Min read
Web Development
Front End Web Development
Client-side Frameworks


React Redux apps are common on the web today due to their versatility, potential to scale, and innumerable features. Using actions and reducers complements your app's architecture and allows you to keep your code clean while implementing complex features. However, when you need to use asynchronous operations, such as dispatching actions after receiving the response from a server, actions and reducers alone aren't sufficient. This guide demonstrates how to interact with asynchronous data in your React Redux app using a Redux library called redux-thunk.

Setting Up App

In this example, you'll develop a simple app that returns a random username as a string from a given array asynchronously. To achieve this you’ll use a middleware called thunk that lets you intercept your actions before it reaches the reducer.

Create a blank React project by running

1npx create-react-app react-thunk-app

Install Redux and react-redux, the core packages for setting up Redux in your React app

1npm i --save redux react-redux

Install redux-thunk to use thunk

1npm i --save redux-thunk

Creating the Store

Import createStore to create a global state for your components along with applyMiddleware to use a middleware in your store. Next import thunk from redux-thunk. Create a reducer rootReducer that takes the state and action and returns the updated state. Pass rootReducer and applyMiddleware functions as parameters to createStore. Finally, to use thunk and simply pass it to applyMiddleware as a parameter. Most of the code inside store.js is self-explanatory and you can see how easy it is so use thunk in your Redux store.

1import {createStore,applyMiddleware} from 'redux';
2import thunk from 'redux-thunk';
4const initState={
5    user:{}
8const rootReducer=(state=initState,action)=>{
9    switch(action.type){
10        case "ADD_USER": 
11            return{
12            ...state,
13            user: action.payload
14        }
15        default:
16            return state;
18    }   
21export default createStore(rootReducer,applyMiddleware(thunk))

Inside index.js import Provider from Redux and pass your store as props to this provider component. You also need to wrap your entire app inside this provider component.

1import React from 'react';
2import ReactDOM from 'react-dom';
3import './index.css';
4import App from './App';
5import * as serviceWorker from './serviceWorker';
6import {Provider} from 'react-redux';
7import store from './store';
10  <React.StrictMode>
11    <Provider store={store}>
12      <App />
13    </Provider>
14  </React.StrictMode>,
15  document.getElementById('root')

Creating Actions

It's a good practice to perform dispatching of your actions inside an action creator. Consider the following code inside the actions.js file that takes in the dispatch and getState as a parameter and dispatches an action of type ADD_USER. It returns the newUser inside the payload property and fetches this newUser from a service called getRandomUse().

1import {getRandomUser} from './service';
5export const getRandomUserAction=()=>async(dispatch,getState)=>{
6    const newUser= await getRandomUser()
7    dispatch({
8        type:ADD_USER,
9        payload:newUser
10    })

Creating Service

You can imagine getRandomUser() as a function that returns a random user from a backend service. For brevity purposes, the below code mimics a backend service and returns a promise wrapped around a random user from a list of users after three seconds. The delay is purposely added to replicate the asynchronous nature of an API response. In a practical scenario, you'll make an API call to your server inside this file to get some data.

1const users=['James','Michael','Harry','Sam','Dubby']
3export const getRandomUser=()=>{
4    return new Promise(resolve=>setTimeout(()=>{
5        resolve(users[Math.floor(Math.random()*10)%users.length])
6    },3000))

Consuming State

Inside main App.js, import connect from react-redux and getRandomUser from your actions.js. Create a function mapStateToProps, which pulls the required state from your store so that it can be passed down as props to your component. Create an object mapDispatchToProps that maps your dispatch to a simple function that can be passed down as props to your component. Call the connect() function and pass mapStateToProps and mapDispatchToProps as parameters. Finally, wrap your app component inside the connect() function. Now your store and actions are ready to be used by your component.

To see this in action create a simple UI button that fires the getUser() function and prints the random user from the state.

1import React,{useEffect} from 'react';
2import {connect} from 'react-redux';
3import {getRandomUserAction} from './actions';
5import './App.css';
7function App({getUser,user}) {
8  useEffect(()=>{
9    console.log(user)
10  },[user])
11  return (
12    <div className="App">
13      <button onClick={getUser}>Get a random user</button>
14      {
15        Object.values(user).length>0 ? user : <>No random user!</>
16      }
17    </div>
18  );
21const mapStateToProps=(state)=>({user:state.user})
23const mapDispatchToProps={
24  getUser:getRandomUserAction
27export default connect(mapStateToProps,mapDispatchToProps)(App);


Using thunk you can communicate with your actions right before they reach your reducer. thunk has a number of use cases built around practical web apps that need to dispatch different actions depending on the response from the server. The example used in this guide can be used as a boilerplate for your React Redux apps where you need to wait for some response from the server before modifying your state.