Blog>
Snippets

Applying Thunk Middleware for Async Actions

Show implementation of a Redux thunk for fetching data from an API and dispatching actions based on the response.
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

// Reducer
const rootReducer = (state = { data: [], loading: false, error: null }, action) => {
  switch (action.type) {
    case 'FETCH_DATA_BEGIN':
      return { ...state, loading: true, error: null };
    case 'FETCH_DATA_SUCCESS':
      return { ...state, loading: false, data: action.payload };
    case 'FETCH_DATA_FAILURE':
      return { ...state, loading: false, error: action.payload };
    default:
      return state;
  }
};

// Create store with thunk middleware
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
This snippet configures the Redux store and applies redux-thunk middleware which allows us to write action creators that return a function instead of an action.
// Action Types
const FETCH_DATA_BEGIN = 'FETCH_DATA_BEGIN';
const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';
Defining action types for the possible states of the data fetching process.
// Action Creators
const fetchDataBegin = () => ({
  type: FETCH_DATA_BEGIN
});

const fetchDataSuccess = data => ({
  type: FETCH_DATA_SUCCESS,
  payload: data
});

const fetchDataFailure = error => ({
  type: FETCH_DATA_FAILURE,
  payload: error
});
These are action creators for each step of the async operation: starting the fetch, handling success, and handling failure.
// Thunk for fetching data
const fetchData = url => {
  return dispatch => {
    dispatch(fetchDataBegin());
    return fetch(url)
      .then(handleErrors)
      .then(res => res.json())
      .then(json => {
        dispatch(fetchDataSuccess(json));
        return json;
      })
      .catch(error => dispatch(fetchDataFailure(error)));
  };
};

function handleErrors(response) {
  if (!response.ok) {
    throw Error(response.statusText);
  }
  return response;
}
This thunk performs the async fetch operation. It dispatches actions corresponding to the fetch's lifecycle: begin, success with the retrieved data, or failure with the encountered error.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Thunk Middleware Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux-thunk/2.3.0/redux-thunk.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
</head>
<body>
<div id="data"></div>
<script type="text/javascript">
  // Insert the JavaScript code from the previous snippets here
</script>
</body>
</html>
This is a simple HTML structure to show where the JavaScript code should be placed (inside the script tag at the bottom).
/* CSS is not included as it does not directly pertain to the Redux thunk example. */
No CSS code is necessary for the example of applying thunk middleware for async actions in Redux.