How to use async methods inside Redux actions using Redux-Thunk

Gustavo Gonzalez
Aug 30, 2018 · 4 min read
Redux-Thunk Flow

If you are using Redux, probably you noticed that actions only can return plain objects, something like:

{ type: HERE_THE_ACTION_TYPE, anObject }

If we try to return any other thing like for example a function, the browser will nicely remember it with a message:

Action must be plain object

In the message, Redux is telling us the solution: Use custom middleware for async actions

This article will help us to prevent the error using Redux-Thunk.

First steps

npx create-react-app demo-react-thunk
cd demo-react-thunk
yarn add redux react-redux redux-thunk

The good stuff

  • An action: it will fetch the user data
  • A reducer: to put the data in the global state
  • An store: to save the global state
  • A component: to show the data

The action

export const fetchUsers = () => {
return dispatch => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(json => dispatch({ type: 'FETCH_ALL_USERS', json }))
}
}

What are we doing there?

Instead of returning a plain object we are returning a function that expects the dispatch method as parameter, the function is asking for some dummy data using https://jsonplaceholder.typicode.com/ service, transform the response to json and then return the plain object action using dispatch. For details about dispatch method, please read the official redux docs

The reducer

import { combineReducers } from 'redux';const user = (state = { users: [] }, action) => {
switch (action.type) {
case 'FETCH_ALL_USERS':
return {
...state,
users: action.json
};
default:
return state;
}
};
export default combineReducers({
user
});

The store

import { applyMiddleware, createStore } from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from './reducers/user';

and then we should create the store with following code:

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

What we are doing here, is asking our store to apply a middleware, remember the original message about using custom middleware for async actions?. The middleware in this case is Redux-Thunk that will help us to run async methods in the action.

The code for src/index.js should looks like the following

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

The component

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { connect } from "react-redux";
import { fetchUsers } from "./actions/user"
class App extends Component {
componentDidMount() {
this.props.fetchUsers();
}
render() {
const { users } = this.props;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Redux Thunk Demo</h1>
</header>
<section>
{
users.length > 0 &&
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{
users.map(user =>
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.phone}</td>
</tr>
)
}
</tbody>
</table>
}
</section>
</div>
);
}
};
const mapStateToProps = (state) => {
return state.user;
}
const mapDispatchToProps = (dispatch) => ({
fetchUsers: () => dispatch(fetchUsers())
});
export default connect(mapStateToProps, mapDispatchToProps)(App);

That's all folks

If you like this story clap as many times as you want, and to see similar stories about technology, check our publications and leave us a comment if you have any question.

If you need a team that can help you to implement your ideas in React JS or React Native, feel free to ping us using our website and filling the contact form.

Gustavo
Mail: gustavo@alturasoluciones.com
Twitter: @Aguardientico
LinkedIn: www.linkedin.com/in/gustavoagonzalez
Blog in spanish: http://aguardientech.blogspot.com

AlturaSoluciones

IT consulting.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store