Blog>
Snippets

Handling Asynchronous Actions with Middleware

Show how to dispatch actions that handle API calls and process the resolved data with redux-thunk in Redux version 5.0.0.
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

// Action Types
const FETCH_DATA_BEGIN = 'FETCH_DATA_BEGIN';
const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';

// 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 }
});

// Thunk Middleware for Async Action
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)));
  };
};

// Handle HTTP errors
const handleErrors = response => {
  if (!response.ok) {
    throw Error(response.statusText);
  }
  return response;
};

// Reducer
const rootReducer = (state = {}, 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.data };
    case FETCH_DATA_FAILURE:
      return { ...state, loading: false, error: action.payload.error, data: [] };
    default:
      return state;
  }
};

// Store with middleware
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
This JavaScript code sets up a Redux store with redux-thunk middleware. It defines action types, action creators, a thunk to handle an asynchronous API call, and a simple reducer. The `fetchData` function is a thunk that dispatches actions to handle the various states of an asynchronous request (begin, success, failure).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Async Redux Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux-thunk/2.3.0/redux-thunk.min.js"></script>
</head>
<body>
<div id="app"></div>

<script type="text/javascript">
// Place the JavaScript code from the previous part here
</script>

<script type="text/javascript">
// Dispatch the async action
store.dispatch(fetchData('https://jsonplaceholder.typicode.com/posts'));

// Subscribe to the store to get updates on the data
store.subscribe(() => console.log(store.getState()));
</script>
</body>
</html>
This HTML file includes the Redux and redux-thunk libraries and sets up a basic HTML structure. The JavaScript code for the Redux setup and async actions should be inserted where indicated. It also dispatches the `fetchData` thunk to initiate an API call and subscribes to the Redux store to log the state to the console when it updates.
body {
  margin: 0;
  padding: 0;
  font-family: Arial, sans-serif;
}

#app {
  margin: 20px;
  padding: 20px;
  border: 1px solid #ddd;
}
This CSS provides basic styling for the HTML body and the `#app` div where the Redux application will interface with the DOM.