There are a lot of approaches we can make to do an API call in React. I will share what I’ve learned and discovered after dealing with different types of making an API call in React. This includes executions through hooks and without hooks.
I’m also here to try and rethink the approaches that we always have but we tend to forget because of the new things. How well do we know the fundamentals?
Without further ado, let’s get started!
👨💻 Designing our Hooks
Before we get started with the different patterns, let’s start designing how our hooks will look like and also discuss why it was structured that way. I will start by creating a specialized API hook to fetch a list of todos.
We structured our hook this way in order to be flexible in different scenarios. The different scenarios will be discussed as we go through the list. I want to say that there are still unknowns and this isn’t perfect, but this is progress.
I know you will be having a lot of questions, here are some I can answer right now on this section, and let’s see if you can get an answer as we go through. If you don’t get an answer, let’s discuss it in another section.
- Why do we have two functions re-exported? One is the
getTodosand another one is the
The reason we did that is to allow the consumer — the one who will be using our hook, to have the ability to execute the API in a “hook way” version or in a “non-hook way” version.
The idea here is that, to be able to reuse the same API core logic across the app. This is helpful when you are dealing with SSR with Next.js or Gatsby or also if you don’t need states into it.
- Should the logic be avoided in the hook implementation?
As much as possible we should avoid some logic on the hook that may alter the behavior of the API call. Let’s say you add some data transformers. It’s better to add that in the non-hook version so that you have one place for it. In that way, we can add test coverage and all consumers regardless if using the hook and non-hook version will benefit from it.
- What is the use of the return value from the hook if the
executemethod returns the data already?
There are scenarios where you need the data immediately on the handler function (i.e onSubmit handler) for extra processing instead of relying on
useEffect. Both are important, but as much as possible if we can do it on the handler function, do it there instead of listening through the
useEffect for changes and react to it.
If the process depends on each other like the 2nd API call needs the result of the 1st API call, it’s hard to “chain” those process together through
Those are the questions I can answer now. I hope some of it gives you a better idea of it. Let’s get started now for the different patterns we will be learning together!
💡 API Call on Component Mount
Scenario: When the user hits the page, we want to hit an API call on the component mount.
Intentionally didn’t wrap the hook in
useEffect because we want to let the consumer decides when to run and how to run. I think that is important to consider. With this approach, we always control the execution and it’s pure. When I say pure, it means we know when and how it is run without going through our hook implementation itself. Which means it is easy to track when it fires off.
💡 API Call on User Event (i.e. onClick, Form Submission)
Scenario: When the user submits the form, we want to do an API call to save the form.
The pattern for doing a POST API call is similar also with how we did the GET API call. They both have the hook and non-hook version exposed so that the consumer has the option to choose between the two on which is appropriate.
Also, the important thing on this hook implementation, if you will observe our
execute method, it returns the data or it throws an error when there is. The return of data is important because there are scenarios where you need the response immediately instead of using a
useEffect. You will see more about this when we go on running API calls in a serialized mode — where one response is needed to the next API call.
💡 API Call on Search Field (autocomplete, table search)
Scenario: When the user types on a search field, we want to do an API call using the value that the user entered.
💡 API Call on Paginate (with a limit)
Scenario: When the user selects a new page on the table, we want to do an API call to get the data on the selected page with the given limit. This can be applied also with other pagination options such as offset or sorting.
💡 API Call on Serialize Requests (2nd API call based on the 1st API call)
Scenario: When the user submits the form, we want to do multiple API calls in a serialize mode to process the form values.
The alternative of this is using the
useEffect pattern, but I think it is incorrect to do that when the request is coming from a user event. What do I mean with that? Let me show you how it will look like on
When we do the
useEffect approach, we need to add an extra flag state to teach our
useEffect how it will react intellectually because if not, it will run infinite times. The inconvenience also on this approach is the resetting of the state value which will probably be tedious as the app grows big.
Here’s another example:
It’s hard to track states, understand the flow or sequence and the error handling is hard. To handle errors using this approach, you have to listen to the error object on each hook and put it inside the
useEffect. This is also prone to infinite re-render. Prone to multiple API requests if not handled correctly. One incorrect flag and then there you go sending multiple API requests.
You might ask, why did I just put everything in one hook? That’s a good question. That will actually work and that is much better than with all these
useEffect . That approach is like putting a lot inside of things into a single plastic. We’re mixing a lot of things and putting a lot of responsibility to that hook. It will be hard to test it and make sure it is doing what it is supposed to do so. It’s hard to reason that. Another reason why I didn’t do that is I want the API hooks to be used interdependently with each other. For example, I want to use API hook A to this page but I don’t want to fire API hook B. It’s hard to do composition at a bigger level when all of those operations are inside a single hook.
🤖 Bringing It All Together
There are a lot of use-cases I’m not yet aware of and so this list can’t provide all of the examples but I think this provides good progress and pattern on how you will work on your API calls on React.
If you will observe most of the examples, it doesn’t have a lot of
useEffect implementations. The reason is, I did encounter a lot of infinite loops already, implemented a lot through it, and got to the point where I realized that there are other options out there. Other options that existed way before this comes up. That option was the non-hook approach. It’s always been there. But, we did substitute it with these new approaches.
I wonder if how many approaches can we solve with the basic approaches? I’m not saying one is good and one is bad. I don’t know a lot to say that one is good and one is bad. I’m trying to see if do I/we really have the right understanding of the fundamentals?
At the end of the day, this isn’t a silver bullet guide on how to perfectly do your API call on React but this will help you strategize or have another option on how to do it in another approach. Try it out and let me hear your experience with it!
Did I miss something? Comment down and let’s work on that!
Thank you for reading. I hope this will help you on your journey! ❤️