Async Loading with Redux Thunk

In this article we're going to continue our look into loading Articles using Redux. We've done the initial setup. Now we're going to use asynchronous actions with a new library, Redux Thunk, to pull the markdown data from an API.

We're going to start where we left off in the last article.
If you need to catch up:

git clone
cd webpack-course
git checkout redux-thunk
npm install

Missing Image

Redux Thunk

Let's jump right in. In the terminal let's install Redux Thunk as well as a fetch polyfill that will work on the client as well as the server:

npm i redux-thunk cross-fetch

Fetching Reducer

Now let's setup our new action, we'll call it fetchArticle and it will be unlike our previous action in that it will return a function. That function contains the dispatch and the getState functions from the store. So this is a way to pass the store to your action for further dispatch and use of the store state.

In actions.js:

import fetch from "cross-fetch"

export const fetchArticle = (site, slug) => dispatch => {
  if (!site || !slug) return
    .then(res => res.json())
    .then(items => dispatch(fetchSuccess(items)))
    .catch(err => dispatch(fetchError(err)))

These kinds of actions don't act normally when you return an action. That won't work and the action will never hit the reducer. Instead we dispatch other actions, that are just plain objects. So we'll add some of those as well. Let's create the actions and corresponding reducer for the fetching.

In actions.js:

export const fetchSuccess = response => {
  return {
    type: FETCH_SUCCESS,
    payload: response

export const fetchFailure = error => {
  return {
    type: FETCH_FAILURE,
    payload: error

export const FETCH_ERROR = "FETCH_ERROR"
export const onError = error => {
  return {
    type: FETCH_ERROR,
    payload: error

In reducers.js:

import { FETCH_SUCCESS, FETCH_FAILURE, FETCH_ERROR } from "./actions"

export const fetchArticle = (state = {}, action) => {
  switch (action.type) {
      return {
        content: action.payload
      return {
        response: action.payload
      return state

Now in store, let's add our new fetchArticle reducer.

In store.js:

import { createStore, applyMiddleware, compose } from "redux"
import { fetchArticle } from "./reducers"
import thunk from "redux-thunk"

const composeEnhancers =
  typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    : compose

const enhancer = composeEnhancers(applyMiddleware(thunk))

export default createStore(fetchArticle, enhancer)

Okay, so now that we've got the Redux code down, let's setup the endpoint. This is a simple MVP that just returns the post parameter in JSON form.

In express.js:

server.get("/api/articles/:post", (req, res) => {

Now let's use the props we've been using already to dispatch this fetchArticle action.

In Article.js:

componentDidMount() {
  this.props.dispatch(fetchArticle(, this.props.match.params.slug))
export default connect(state => ({
  content: state.content

In Sum

Okay, so we've done a great deal here. We've added Redux thunk to our store to use asynchronous actions to pull the data from our server endpoint. We also added hot reloading of the reducers in development.

If you need the final code:

git checkout redux-thunk-final

Up Next

Next we'll be completing this API endpoint to serve the real markdown data back to our client. We've got a good test setup, so we know it's working. It's time to finish the job. See you there.