This Redux Thunk example is the bare minimum it takes to get a React application up and running with asynchronous redux actions. It is under 100 lines and consists of just two files (with dependencies).

These two files will show you start to finish how to make a redux store, create some async/sync actions, and connect them to a component.

It's the simplest example of the entire React, Redux, Redux Thunk lifecycle I could come up with.

This post is also a follow up to Super Simple React Redux Example this post and the previous one are very similar so you can flip back and forth to see the difference between Redux with and without thunks. This should make it much easier to determine what is going on.


Option 1: Do it yourself

npm install -g create-react-app
create-react-app my-simple-async-app
cd my-simple-app
npm install --save redux react-redux redux-thunk
echo '' > src/redux.js

Option 2: Clone my repo

git clone
cd my-simple-async-app
npm install
npm start

Option 3: Play in CodeSandbox


This file contains the store, actions, and reducers all wrapped up into one. For more advanced applications with more actions you would break this file up into parts.

I've put file name comments above each section to illustrate where they would go if you were to break them up into separate files.

We're also going to use Redux Thunk to asynchronously fetch the most recently updated repos by username from Github using this REST URL:

You can check out the Github API documentation on the repos endpoint here:

import { applyMiddleware, combineReducers, createStore } from 'redux';

import thunk from 'redux-thunk';

// actions.js
export const addRepos = repos => ({
  type: 'ADD_REPOS',

export const clearRepos = () => ({ type: 'CLEAR_REPOS' });

export const getRepos = username => async dispatch => {
  try {
    const url = `${username}/repos?sort=updated`;
    const response = await fetch(url)
    const responseBody = await response.json();
  } catch (error) {

// reducers.js
export const repos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_REPOS':
      return action.repos;
    case 'CLEAR_REPOS':
      return [];
      return state;

export const reducers = combineReducers({ repos });

// store.js
export function configureStore(initialState = {}) {
  const store = createStore(reducers, initialState, applyMiddleware(thunk));
  return store;

export const store = configureStore();

Take note of the Redux Thunk specific pieces above. First notice the applyMiddleware(thunk) call. This tells redux to accept and execute functions as return values. Redux usually only accepts objects like { type: 'ADD_THINGS', things: ['list', 'of', 'things'] }.

The middleware checks if the action's return value is a function and if it is it will execute the function and inject a callback function named dispatch. This way you can start an asynchronous task and then use the dispatch callback to return a regular redux object action some time in the future. Think of it like this:

// This is your typical redux sync action
function syncAction(listOfThings) {
  return { type: 'ADD_THINGS', things: listOfThings  }

// This would be the async version
// where we may need to go fetch the
// list of things from a server before
// adding them via the sync action
function asyncAction() {
  return function(dispatch) {
    setTimeout(function() {
      dispatch(syncAction(['list', 'of', 'things']));
    }, 1000);


I've put the React component and the Redux "container" connection logic into one file for clarities sake. If you want you can break the two sections up into separate files by referencing the filename comments I've added.

import React, { Component } from 'react';

import { connect } from 'react-redux';

import { getRepos } from './redux';

// App.js
export class App extends Component {
  state = { username: 'tylerbuchea' };

  componentDidMount() {

  updateRepoList = username => this.props.getRepos(username);

  render() {
    return (
        <h1>I AM AN ASYNC APP!!!</h1>

        <strong>Github username: </strong>
          onChange={ev => this.setState({ username: })}
          placeholder="Github username..."
        <button onClick={() => this.updateRepoList(this.state.username)}>
          Get Lastest Repos

          {, index) => (
            <li key={index}>
              <a href={repo.html_url} target="_blank">


// AppContainer.js
const mapStateToProps = (state, ownProps) => ({ repos: state.repos });
const mapDispatchToProps = { getRepos };
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App);

export default AppContainer;


You'll also need to update your index React component to connect Redux to your application. It is a simple two step process and looks like this:

import React from 'react';
import ReactDOM from 'react-dom';
import AppContainer from './App';
import './index.css';

// Add these imports - Step 1
import { Provider } from 'react-redux';
import { store } from './redux';

// Wrap existing app in Provider - Step 2
  <Provider store={store}>
    <AppContainer />