In most production web applications, data come from remote services. So you cannot get the data right away. There are a couple of ways to handle async operations in Redux, such as “redux-saga,” “redux-promise,” etc. But the “redux-thunk” is simple and effective for most scenarios.
Bad Code
// Action Creator
import axios from "axios";
export const fetchPosts = async () => {
const response = await axios.create({
baseURL: 'https://mydata.com'
}).get('/data');
return {
type: 'FETCH_DATA',
payload: response
}
}
If you run the code, you will get an error: Actions must be plain objects. What’s wrong with this code?
- The “async – await” syntax does not return a plain object behind the scenes.
- When we remove the “async – await“: When the action gets to a reducer, the fetched data is not available yet.
To solve this issue, we can use middleware to handle the async request.
- Synchronous Action Creator: returns an action object instantly
- Asynchronous Action Creator: Used when it takes some time to get the data (mostly through a network)
redux-thunk
A thunk is a computer science term. It is a function that wraps an expression to delay its evaluation.
The “redux-thunk” package allows you to write action creators (functions to create actions) that return a function instead of an action, and then you can execute the dispatch() later.
Setting up Thunk
“redux-thunk” is a middleware in Redux.
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
Structure of redux-thunk
The main idea of the redux-thunk is that you can return a function in action creators. This inner function can have 2 parameters (dispatch and getState) that are from the Redux store.
const action1 = (data) => {
return {
type: 'myAction',
payload: data
};
};
const asyncAction1 = () => {
return (dispatch, getState) => {
dispatch(...);
};
}
Async Operation with Thunk
The most common usage of the “redux-thunk” is async actions.
const asyncLoad = () => {
return (dispatch) => {
return apis.loadData().then( data =>
dispatch({
type: 'load',
payload: data
});
)).catch(error => { ... });
};
}
Or you can use async-awit syntax.
const asyncLoad = () => {
return asynch (dispatch, getState) => {
const response = await apis.get('/data');
dispatch({
type: 'load',
payload: response
});
};
}