A Beginner’s Guide to Redux Thunk: Async Logic and Data Fetching from an API with Thunk.

Koray Ozkal
6 min readJan 9, 2021

If you have watched Dan Abramov’s instructional videos, read the official documentation, but are still puzzled by the “Thunk” concept — Don’t worry this article is here for help!

THUNK/THəNGk/ — verb, past tense: thunk; past participle: thunk “nonstandard or humorous past and past participle of think.”

Oxford’s English dictionary

Synchronous or Asynchronous, that is the question!

If you are familiar with React.js you might have noticed that by itself, a Redux store doesn’t know anything about async logic. It only knows how to synchronously dispatch actions, update the state by calling the root reducer function, and notify the UI that something has changed. Therefore, any asynchronicity has to happen outside the store.

If you are working on a beginner’s app and all the data you might need has been directly inside of your React Redux client application, then there is no problem. However, applications we come across in real life need to work with data from a server, by making HTTP API calls to fetch and save items. This causes a huge problem because Fetch requests in JavaScript are asynchronous. When retrieving data from APIs, we will run into a problem where the action creator returns an action before the data is retrieved.

To resolve this, we need to use a middleware that can enable us to write some kind of async logic that interacts with the Redux store. Thankfully, , Redux already has an official version of that “async function middleware”, called Thunk.

What is “Thunk”?

A “thunk” as a programming concept is a small function that generally returns another function. That function can then be called at a later point, similar to a callback. Redux Thunk is a middleware that greatly benefits this concept. It lets you call action creators that return a function instead of a plain JavaScript object. That returned function receives the store’s dispatch function, and with that, we are able to dispatch multiple actions: One to place the state in a loading state, and another to update our store with the returned data.

“I thunk, therefore I am.”

Koray Ozkal, 2021

I am currently working on a comic book app on React Redux. Let’s walk through the steps to see if we can successfully utilize Redux-Thunk to fetch data from an API. But first, we need to install and then set up Redux-Thunk middleware.

How to Install and Setup Redux-Thunk?

Redux-Thunk can be installed by running

npm install --save redux-thunk

or by typing the command line below in the terminal

yarn add redux-thunk

Then, wherever you have your Redux setup code, you need to import redux-thunk and insert its middleware into Redux:

// src/index.jsimport React from 'react';import ReactDOM from 'react-dom';import { Provider } from 'react-redux';import { createStore, applyMiddleware } from 'redux';import thunk from 'redux-thunk';import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store} ><App /></Provider>, document.getElementById('container'))

As you might notice we just imported a new function named applyMiddleware() from redux.

import { createStore, applyMiddleware } from 'redux';

along with thunk from the redux-thunk package,

import thunk from 'redux-thunk';

and passed in applyMiddleware(thunk) as a second argument to createStore.

const store = createStore(rootReducer, applyMiddleware(thunk));

Normally, in Redux our action creator returns a plain JavaScript object, but now Thunk will allow us to return a function inside of our action creator. That function receives the store’s dispatch function as its argument and we can dispatch multiple actions from inside that returned function.

Let’s use https://api.shortboxed.com/ as our API source, the data we will use looks like this.

comics:
[
{
publisher: "MARVEL COMICS",
description: " Showdown on Wall Street!",
title: "CAPTAIN AMERICA SAM WILSON #6",
price: "$3.99",
creators: "(W) Nick Spencer (A) Joe Bennett (CA)
Oscar Jimenez",
release_date: "2016-02-03"
},
{
publisher: "DC COMICS",
description: "Let the doctor make you strong, ",
title: "BATMAN BEYOND #9",
price: "$2.99",
creators: "(W) Dan Jurgens (A) Bernard Chang (CA)
Philip Tan",
release_date: "2016-02-03",
},

]

Let’s create our App.Js

The component’s main purpose is to render JSX. It uses data from Redux via mapStateToProps() and connects an onClick event to an action through mapDispatchToProps():

// ./src/App.jsimport React, { Component } from 'react'import { connect } from 'react-redux'import { fetchComicbooks } from '../actions/// ./src/App.jsimport React, { Component } from 'react'import { connect } from 'react-redux'import { fetchComicbooks } from'../actions/fetchComicbooks'class App extends Component {handleOnClick() {this.props.fetchComicbooks ()}render() {const comicbooks = this.props.comicbooks.map(comicbook => <li key={comicbook.id}>{comicbook.title}</li>);return(<div><button onClick={(event) => this.handleOnClick(event)} />{comicbooks}</div>);}};function mapDispatchToProps(dispatch){return { fetchComicbooks: () => dispatch(fetchComicbooks ()) }}function mapStateToProps(state){return {comicbooks: state.comicbooks}}export default connect(mapStateToProps, mapDispatchToProps)(App)

Below are the steps we would like to happen when the user calls the API:

  1. Invoke fetchComicbooks()
  2. Directly after invoking fetchComicbooks() dispatch an action to indicate that we are loading data.
  3. Call the fetch() method, returning a Promise that we want to resolve.
  4. After the Promise resolves, dispatch another action with a payload of the fetched data that gets sent to the reducer.

What happens when the onClick event is fired? All of that logic is handled outside of the component, in our fetchComicbooks() action:

// actions/fetchComicbooks.jsexport function fetchComicbooks() {return (dispatch) => {    dispatch({ type: ‘START_ADDING_COMICBOOKS_REQUEST’ });    fetch(‘ https://api.shortboxed.com/comics/v1/new').then(response => response.json()).then(comicbooks => dispatch({ type: ‘ADD_COMICBOOKS’, comicbooks }));};}

dispatch() is passed in as an argument. There are two calls to dispatch(), first passing in { type: 'START_ADDING_COMICBOOKS_REQUEST'} before the fetch() call, then passing in { type: 'ADD_COMICBOOKS', comicbooks } inside .then(). By having both dispatch() calls, it is possible to know just before our application sends a remote request, and then immediately after that request is resolved.

And finally, we need our Reducer

// ./src/astronautsReducer.jsfunction comicbooksReducer(state = { comicbooks: [], requesting: false }, action) {switch (action.type) {case 'START_ADDING_COMICBOOKS_REQUEST':return {...state,comicbooks: [...state.comicbooks],requesting: true}case 'ADD_COMICBOOKS':return {...state,

Now if our request is true, we could display a loading message in JSX.

I hope this article helped you to cover some Async logic behind using Redux-Thunk. Happy coding and please let me know if you have any comments or suggestions!

Resources:

https://www.freecodecamp.org/news/redux-thunk-explained-with-examples/

--

--

Koray Ozkal

Marketing Strategist @Intel, Tech Blogger, Rock Guitarist, Hockey & Basketball fan.