In this lesson we’ll learn how to perform an Ajax request to an external API in response to an action in the redux store. We’ll see how, within the epic, we get access to actions after any reducers have been executed and how we can convert that incoming action into a resulting one that will save the data received into the redux store.
This application here contains a user's component that is connected to the Redux store. There's just a single reducer in the store at the moment, with a default state containing a user's array. That is three user names from GitHub. Current, which will be populated with the user's data by default it sets a "no." And a loading state which defaults to false.
Now, let's implement a feature where clicking the "load user" button will fetch the data from an API. Now, actions, and more specifically action names are the glue between Redux and Redux observable. I'd like to start by defining those first. We'll define the action names or the types first -- "export const fetch user." We'll have one called "fetch user fulfilled."
For this example, we're just going to deal with two states. It's going to be when you click on one, we're going to fire the "fetch user" action. And we'll perform an ajax call to the API. When that returns, we'll fire the "fetch user fulfilled." Now, in any part of our application dispatches actions of these types. They have different payloads. We'll create functions to define that in one place.
We'll say the "fetch user" action returns an object that has a type property set to fetch user, and it's payload...What is the payload? If we look back in our data, you can see that we have this user's array which is three GitHub user names. I happen to know that the API refers to these as log ins. We'll say here that we accept our log in, and we'll pass that through as the payload.
Now, for the "fetch user fulfilled" action, we can copy that, change the function name and the type. For the payload, this will be the response from the API. We can change this to "user." The next step is to wire up these buttons, so that clicking on one will dispatch the "fetch user" action into the store. Back in the user's component -- here is the button. We can say "unclick," and provide a function that calls "props.load user". We'll send through the item. While we're here, let's rename this item.
As we know, it's actually the log in. This load user function does not yet exist in the props. We'll go down to the map dispatch function that we can provide to the connect method of Redux, and add that. We said "load user." This will be a function that will dispatch the "fetch user" action and pass through the log in. If we import this, which one currently work because we need to go back and export both of these. Try that again, hit save. Now, we're good to go.
If we bring up Dev tools, and switch to the Redux DevTools, then click a user, you can see that the action is firing. We can look at the payload. We have SubStack. If we click on "Shaky Shane," we get another action. There we have it. That verifies the actions are going into the store correctly. Because this API call could take some time, we should set the loading state to "true" the moment a button is clicked.
In the reducer, we can say "case fetch user." We can define the state changes we want to make when fetch user occurs. The first thing we want to do is spread it in the existing state. Next, we'll set the "current" to "no" and the loading state to "true." Let's try that out. There you can see we have the loading state. This will never disappear because we're never setting this back to "false" or making the ajax call to get the user. We'll do that next.
We'll open up the index file and find the epic directory. We'll add a function that can react to that "fetch user" action. Let's call it "fetch user epic." It takes that stream of actions. We'll return, actions off type. We can use the constant "fetch user." We'll do a switch map. This gets access to the action. We can destructure from that the payload, and we'll return "obervable.ajax.getJSON."
This is just a convenience method that will automatically give you the response in JSON format without having to pluck it out of anything else. The API we're using is GitHub's. We can paste the first section of that. We'll send in through the log in as the payload here. We can use that here. Should this return successfully, we want to convert the response into an action that has the response in it. We can call "map." This will have the user as the response.
We can return a call to this function which will generate the action for us. Import it, and we'll add this "fetch user epic" to this called "combined epics" which will register in the application. If we test this in a browser, we can open up the network panel, click "load user." We can see that we do get a successful response.
However, the UI stays in the loading state. That's because we need to handle the "fetch user fulfilled" action in the reducer. If we come back over here, we can copy this. Say "fetch user fulfilled." Current will be "action.payload." Loading will be false. When we try it again, it works as expected.
Sadly, this is all out of date now, and there are even issues with the current rxjs implementation of ajax. Further it seems, redux-observable isn't implementing those changes.
One was this .map
nested? It was not necessary
This is epic!