Tutorial using redux-thunk to call API
Continuing from the last Redux tutorial, in this tutorial we will have our app retrieve some ToDo items using axios utility. We will retrieve from this API endpoint: https://jsonplaceholder.typicode.com/todos?userId=1&completed=false
which will give us 9 made-up ToDo items…
Because this will be an asynchronous call, we need to use redux-thunk or redux-saga or equivalent. We will use redux-thunk.
- Hence run the following install …
npm install redux-thunk axios
2. We want to fetch data when the ToDo component mounts. So add componentDidMount …
3. That means that we need to have a prop called fetchToDos. We add it to mapDispatchToProps …
4. This means that we need to have a corresponding function also called “fetchToDos” in the actions.js file…
These functions are action creators. They are supposed to return an action object such as how the function addToDo is doing it. But the fetchToDos is returning another function. This is only possible if we add “redux-thunk” as a Redux middleware.
5. We add it when we create the store by using the third “store enhancer” parameter like this …
6. Our compiler is complaining about not finding fetchToDos in the ToDo component. We better import that function from the actions.js…
At this point our app should run and when ToDo mounts, you see “should fetch ToDos here” in the debug console. So far so good.
7. Before we call the API to fetch ToDos, let’s display “loading…” message to the user interface. We need to dispatch an action to signal loading by adding another action creator called “itemsLoading”…
We dispatch this action creator in fetchToDos (shown above). Passing true to the action creator, the itemsLoading action creator return the action type ITEMS_LOADING and a boolean “loading” state.
8. Add the loading state of false to the initial state when creating the store in appStore.js…
9. Then add ITEMS_LOADING type in actionTypes.js …
10. With the action type ITEMS_LOADING defined, we need to add a case for it in the reducer.js …
The reducer returns a new state just like the original but with the “loading” state changed to whatever was delivered in the action.loading payload.
11. Next we want to change the user interface to display the “loading…” message when the “loading” state is true. Hence map the loading state to the loading prop in the mapStateToProps function of ToDo.js…
12. Now we have this.props.loading to use like this …
We display the loading message when the loading prop/state is true.
13. Run the app and you see that it is in the loading state …
14. Now let’s actually do the fetch by using axios. Import axios into actions.js …
15. Then call it in fetchToDos and get “response.data”…
By looking at the results of jsonplaceholder (screen shot way at the top), we see that it returns ToDo objects, of which we just want the “title” property from it. That is why we use response.data.map to get an array of strings in “items”. If you run app and console.log out “items”, you can see …
16. We want to load those into our ToDo array in our store. Anytime we want to update the store, we have to create an action creator. We call this one “addToDos” which will add an array of ToDos — not to be confused with “addToDo” which adds only one ToDo. Here we write “addToDos”…
Add the constant in actionTypes…
Import in reducer …
Add case for “ADD_TODOS” in reducer …
Because we had added additional state such as “loading”, when we return new state, we need to maintain the other existing state properties. That is why you see “…state” in the case for ADD_TODOS. We also need to add it to ADD_TODO case.
17. Now we can finally dispatch addToDos…
18. Run the app, and you see that the ToDos from jsonplaceholder is loaded, but the loading message is still showing. We turn off the loading message …
19. Now app is working …
20. One last thing is to handle the error case in case the API call fails by adding axios catch clause…
Add itemsError action creator …
Add to actionTypes …
Add to reducer …
Add “error” state to initial state…
Maps error state to error prop …
Display error message when error state is true…
You can test the error case by passing in an invalid API url.
Whew… that was a lot. Time for some redux-thunk humor. You can get the source files linked here.
In the following tutorial, you will learn about combining reducers.