How to Create an API Store in React Native with Axios

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Building React Native Apps for Mac course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Building React Native Apps for Mac, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Building React Native Apps for Mac

So now that we have our mock server running, now is the time for us to add the networking code to our application. By the full React Native comes with the fetch interface, which allows you to do network requests, but we're not going to use it because it's API, it's a little bit awkward. So we're going to go with a better alternative, it's called Axios. It's just a different networking library. So we're going to start by adding Axios to our dependencies. So on your console, you just do our yarn at Axios. That's going to fetch it. And now we're going to create the API store. I'm just going to take the code on the lesson and I'm going to create it on the stores folder. So let's just go over the code. First of all, I import Axios. Then I'm going to import the root type from my store. It's very similar to what we did with the UI store. Then we have the main function of the store, which is create API store. Again, it takes the root store instance as a parameter. And inside of the body, we have our store proper with two properties. One is the fetchbooks and another is the addbook. So fetchbooks is going to do whatever its name says, it's going to fetch the books. So it's an async function. There's a link on the lesson if you need to read a little bit more about async functions. But basically, because the server can take a little bit of time to respond, we have to wait. So we have to give the JavaScript thread back so it can do update or UI and all the other stuff while we wait for the server to return the response. So that's why we have marked the function as async. And inside of it, we have our response object, which we're going to tell it to await for the server to respond. And we have Axios. We tell Axios to get our previous endpoint. We already explored it, right? It's going to return the array of books. And lastly, I'm going to return the data property. This is just where Axios puts the body of the response. And we're going to use that from our component. The ad book is a little bit similar. This time it's going to take a title, which is a string. And this time I have also surrounded the networking code with a try and catch, just as an example, right? So something might go wrong. The title might be empty. The server might encounter some sort of error. So what you want to do to catch all the errors is wrap all your networking calls inside of a try catch. Again, it's fairly similar. We just tell Axios to do a post request. We pass the URL. And we pass the body that we want to send to our backend. And we tell it to await. Afterwards, we just return the body of what our server has returned. So I am going to add the export from our API store. So we can access it from different parts of our code. And I am also going to go into my root store. And I'm going to actually create the instance of an API store. So I already modified the import before. Now I'm just going to add it at the create API store to it. I'm going to add a new property to the type. I'm going to say this is the return type of the type of the create function. And on my store proper, now it's the time to create the instance. So that's all it takes for me to add one more store instance into our root store, right? So let me just check the lesson quickly to see how we're doing. I have my root store. Okay. So now is the time to move to our UI store. So let me just take this code. And I'm going to go into our UI store. So before our UI store used to be the central repository for the book data. Now our UI store is going to reflect what we have on the backend. So every time we want to add a book, we'll call the UI store, but the US store inside of it is going to call the server either to fetch the data or to add more data. And it's just going to be sort of this semi synchronized state with our server. So I just copy them, paste it entire thing and we're going to go over it. So the first change you will see is that I have created a new interface, which I called iBook. And it's just going to reflect the type of the book. Has a title, which is a string. And it has a created that which is also a string. So inside the four store, a few things have changed. Now our books are ready. It's going to be initialized as an empty array. That's when our application starts. But we're going to help the compiler a little bit, right? And we're going to tell it this, even though this is an empty array, it's going to be filled with books. Next we have our get uppercase books function that hasn't changed at all. That's still the same. Whatever is on the books is going to be uppercase. The titles are going to be uppercase. So now I have changed the add books function. So the add book function is still going to take a title. But here we see how we can communicate between stores. So this time I have marked this as async because again we need to wait for the response from the server. So whenever I want to add a book, now I'm going to go into my root store, into my API store, and I'm going to call the add book function with the title that I get passed. And I need to await that response. Once I have that response, I need to, I will just check, you know, if everything's all right, if the server has returned some data, and if it has returned some data, then I 'm going to put it into my books array. Now you will see this run in action function. This comes from Mobx. The problem is that because JavaScript is single threaded, when we do an await, when we deal with promises, which are different JavaScript constructs inside of it, this is just a promise. So whenever we await for a promise, the JavaScript thread kind of loses the context. So even though this looks like a single chunk of code, after the await, something else might have changed, right, in our store with our observables and everything. So the state might be unsynchronized. So that's where running action comes. So let's go back a little bit and think our add book function has been marked as an action with makeout observable. But since we have waited, all the code that is after the await is no longer guaranteed to run in a safe manner, right, in a way that your state is going to be updated correctly. So that's what running action does. It kind of creates this tiny action inside any function. So I'm just going to pass a function to it. And inside of the function, I'm just going to update my books as if nothing had happened, right? So it's just an action within an action that might have lost the guarantees to make sure that the state can be correctly updated. Then I also added a fetchbooks function, which again just kind of calls the API store fetchbooks and just stores whatever the server returns inside of it. So here you can see in practice what I mentioned before, which is that all the net working code remains within a single layer, which for us is our API store, right? Here I don't see any HTTP codes. I don't worry too much about how the URLs look like, right? If I someday decide to change it like I'm not going to use HTTP pure rest responses anymore, I'm just going to use GraphQL. All I have to change is this layer. So let me just go ahead and save that. So going back to the course, here you can see we talked about running in action . And now the time has come for us to connect our UI. So I'm just going to take this code and let's go over it. So I'm just going to take the code from the lesson, going to paste it and let's go over it very quickly. So we have changed a couple of things in the body of our function. Here is our first encounter with hooks, hooks are the integrated way in react of how to handle state. So there is a bunch of hooks. We're not going to go all over all of them because it's just way too many and they're fairly complex. So we're just going to use two hooks right now. One is the use state hook and the use effect hook. So the use state hook, like its name says, it's meant to hold a piece of state. Right now we're passing an empty string and it's going to return an array with two values. The first value is the variable itself, which right now has an empty string. And the second value is a function, which is going to allow us to update the value. So as our components render, we can just call set title, pass it a new value and on the next render cycle, this title value, which is on the first position, is going to change. Next we have our use effect hook. So use effect takes two values. The first value is a function and the second value is an array of parameters. So in our case, our second value is an empty array. That is because we don't have anything to react to. Right? So basically what this is going to do with an empty array is just going to run once. Whenever our component has finished mounting for the first time, use effect is just going to run the function inside of it. So in our case, we're just telling it to fetch the books. Right? So this entire logic that we had under UI store is going to call to our API store. It's going to store the books inside of it. Basically this is just going to run once, once our book books container mount. Right of the actual UI code, not much has changed in how we render the books. We still access in the uppercase books, but we have added a text input. So the user or us, we can add some text in there. The value is going to be the title, which is going to be returned by the use date function. And we have an unchanged text function. So whenever the text inside of this text input changes, we're going to pass it the set title function and this is going to set it as a state. And finally on our bottom, we have changed the on-premise function. So we're now calling the add book function, but with the title itself. So the user type something, we update the local state. Whenever the button is pressed, we send it to our server. It's fairly straightforward. So if I save this now and I go into our application, you will see, well, right now the text input is invisible because we haven't applied any styling to it, but I can just type something. Right? So let's just say my favorite book. This is something that I want to add. I press the button and it's added there. So if I reload the application now, you will see that it's there, some recent splicing there, maybe I clicked twice. But it doesn't matter. So the thing is that this is now saved on the server. Right? So I can just go what's another book. Neuro-minus-serve or something like that. It doesn't really matter. And I can reload it again and it's there. So the server is taking no requests, it's saving the data, right now it's mocked. And whenever our application mounts and this component, the specific mount is going to fetch the books from our server. So let's just talk a little bit about hooks. Now it's the right time. And you might be wondering, well, we can save state within the component and we can kind of observe things, right? This basically an observer. Why did we use mobx? Why did we go through the trouble of setting up mobx? The problem is that as your application grows, using just hooks becomes quite complex, right? So if I just have to pass a title into a child component, that's fine, right? But as you go having more state within your component, as you go having more use effects into your component, it gets really hard to reason about all this stuff because anything can change, anything can cause your component to a re-render, right? So you might change this one and this in state might change another thing, right? So that will cause a re-render. So it's just really hard to reason about this. That's why I prefer to use mobx because it's disconnected from the UI, disconnected from the render cycles. So it makes it a lot easier. My advice is you can use hooks. That's completely fine, but use them for the really local stuff, right? Like for example, on our case, on our books component, this is fairly small, right? The title and the set title function, nobody else need to know knows about this , right? Because this is just on a text input that's being used in the same component. So for this kind of stuff is completely fine. Use effect as well. Right now we're just ruining a single use effect, right? Whenever the component mounts, this is the mechanism that we use to trigger some action. So for this kind of use cases, hooks are completely fine. [BLANK_AUDIO]