Redux-Thunk: A better way to fetch data
Fetching data is Redux apps can be streamlined by using redux-thunk. We are going to use redux-thunk to fetch weather data
We'll cover the following
The idea behind redux-thunk
is that we return a function from an action that gets passed dispatch
. This allows us to do asynchronous things (like data fetching) in our actions:
function someAction()
// Notice how we return a function – this is what's called a "thunk"!
return function thisIsAThunk(dispatch) {
// Do something asynchronous in here
}
}
First implementation
Let’s try to write an action called fetchData
that fetches our data! Start with the basic structure:
// actions.js
/* …more actions here… */
export function fetchData() {
return function thunk(dispatch) {
// LET'S FETCH OUR DATA HERE
}
}
Now let’s copy and paste the xhr
call from the App
component and put it in there:
// actions.js
/* …more actions here… */
export function fetchData() {
return function thunk(dispatch) {
xhr({
url: url
}, function (err, data) {
var body = JSON.parse(data.body);
var list = body.list;
var dates = [];
var temps = [];
for (var i = 0; i < list.length; i++) {
dates.push(list[i].dt_txt);
temps.push(list[i].main.temp);
}
self.props.dispatch(setData(body));
self.props.dispatch(setDates(dates));
self.props.dispatch(setTemps(temps));
self.props.dispatch(setSelectedDate(''));
self.props.dispatch(setSelectedTemp(null));
});
}
}
Now we need to fix three things: 1) We need to import xhr
, 2) we need to get the URL from the action and 3) we need to rename all self.props.dispatch
calls to dispatch
:
// actions.js
// REQUIRE xhr
import xhr from 'xhr';
/* …more actions here… */
// PASS URL IN HERE
export function fetchData(url) {
return function thunk(dispatch) {
xhr({
url: url
}, function (err, data) {
var data = JSON.parse(data.body);
var list = data.list;
var dates = [];
var temps = [];
for (var i = 0; i < list.length; i++) {
dates.push(list[i].dt_txt);
temps.push(list[i].main.temp);
}
// RENAME self.props.dispatch TO dispatch
dispatch(setData(data));
dispatch(setDates(dates));
dispatch(setTemps(temps));
dispatch(setSelectedDate(''));
dispatch(setSelectedTemp(null));
});
}
}
Well, that was easy! That’s our thunked action done – let’s call it from our App
component:
/* … */
class App extends React.Component {
fetchData = (evt) => {
evt.preventDefault();
var location = encodeURIComponent(this.props.location);
var urlPrefix = 'http://api.openweathermap.org/data/2.5/forecast?q=';
var urlSuffix = '&APPID=dbe69e56e7ee5f981d76c3e77bbb45c0&units=metric';
var url = urlPrefix + location + urlSuffix;
this.props.dispatch(fetchData(url));
},
onPlotClick = (data) => { /* … */ },
changeLocation = (evt) => { /* … */ },
render() { /* … */ }
});
/* … */
That makes our App
so much nicer to work with already!
Wiring it up
The last step is wiring up redux-thunk
. redux-thunk
is a so-called “middleware”. Middlewares sit in between the action and the reducers, every action you dispatch gets passed to all middlewares you add. (that’s why they’re called middle ware)!
Now let’s apply
the thunk
middleware in our createStore
call in index.js
:
// index.js
/* … */
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
/* … */
var store = createStore(
mainReducer,
applyMiddleware(thunkMiddleware)
);
/* … */
And that’s it, everything should be working again now. Look how easy it is to handle our components, how nicely everything is separeted by concern and how easy it would be to add a new feature to our app! That’s the power of redux, our application is easier to reason about and to handle, instead of having one massive top-level App
component we separate the concerns properly.
Here’s our Redux app in action
Get hands-on with 1400+ tech skills courses.