React Reusable API Calls With Custom Hooks | by Stefan Mares | Aug, 2022

Using Typescript obviously

Photo by Tatiana Rodriguez on Unsplash

Table of contents:

HTTP provides a set of methods through which web browsers can communicate with web servers. There are 4 popular/well-known methods: GET, POST, PUT, and DELETE. We will discuss GET and POST in this article, but there are much more.

GET: As the name stands for itself, is designed as a safe operation that retrieves some data from the server.

POST: This method allows us to send some data to the server, for example, to add a new entity to a database.

When React switched to functional components it gave us some really cool and powerful tools to build logic, manage state, and design UI much easier and faster. The so-called hooks are some special functions that come directly from the React library. There is a convention that says that the hooks must start with the use prefix so that they can be easily identified.

One of them is useState which helps us to preserve dynamic data between rerenders.

Another one is useEffect which allows us to perform side effects such as making calls to an API, interacting with the local storage, working with timers(setInterval/setTimeout), etc.

And there are more: useCallback, useMemo, useRef, etc. We won’t discuss them in this article.

A custom hook is a special function that we create and it makes use of the hooks provided by React inside its implementation. This approach makes the code reusable and also hides logic from the component, making the code clean and the component easier to read, understand and maintain.

Why TypeScript?

Because it gives features such as type checking allowing us to shape an object so that we have a faster and clear understanding when we deal with variables. It also has compilation errors so that we can tackle them before going into the browser and seeing the errors in there.

As we saw earlier, GET is used to retrieve data from the server. In React this could be achieved with two of its most known hooks: useState and useEffect. With useState we can keep track of the retrieved data, of any potential errors, or if the data is still on its way. With useEffect we can perform the actual call to the server.

Seems like a lot of logic is to be handled by the component. Let’s extract it in a custom hook and make our code clean.

Let’s see what happens here. Our custom hook takes 2 parameters:

  • The actual query string (https://myserver/myroute)
  • The second one is a map function. Its purpose is to shape the raw object of type any, that was returned by the server, to our model from the client side. Some advantages of doing this would be that we can make use of TS features and always clearly see the properties of an object; also, maybe the object returned from the server has more properties than we actually need, or it has a slightly different structure. What is more interesting here is the return type of the function, of type T. This represents a generic type meaning that the function must return an object of our specified type when we actually called the hook. Notice the <T,> from the function(hook) definition? This means that our hook is a generic function.

We can see here how we define our model and an example of the map function:

Next, we see three useState hooks defined. The first represents the data that will be received from the server. We can see again here the generic(T) type.
The second is just a boolean to flag if the data is still loading and the last one will hold any potential error that might appear; either from the server or from our code below.

Following, we have the useEffect hook that is doing the API call. First, we set the loading flag to true to indicate that the data is being fetched. Then we make the actual call. After the call, we map the data to our shape and set the loading flag back to false to indicate that the call has ended.

In case of any error, we set the error message and put the flag back to false.

In the end, we return the 3 objects: data, loading flag, and errors. Then, in the component, we can use it in the following manner. If the loading flag is true then we show some loading indicators. Otherwise, if we have errors display some user-friendly error message. If not, we can happily display the data.

What is interesting here is the use of generic types and of map function. In case we need to make a call to a different API we just call the hook with the specific query and implement the function that maps our data.

This is how we use the hook:

Now, things in the above hook implementation, of course, could be implemented differently. The state can be grouped in one instead of three. We can verify the response status and return things accordingly or even use an error handler callback. We can add the options parameter for the fetch. So on and so forth, may the reader of this article decide what is best for its own scenario.

The hook design and implementation for POST are slightly different from GET, but not too much. Since it’s sending some data we can define a model of the data to be sent via the body. Of course, it may have also response data.

Let’s discuss the differences.

First, we have 2 generic types now: BodyData and ResponseData. BodyData is used for shaping the body object that needs to be sent to the server and the ResponseData is used to shape the response data from the server.

Another noticeable difference in this hook implementation is the usage of useCallback hook instead of useEffect. Here, useCallbacks wraps the API call function, and our custom hook returns it. We do this wrapping to memoize the function returned by our custom hook in case it is passed to a child component, to prevent useless rerenders, because every time a React component re-renders, its functions get recreated.

Now we can call this method on a button click, for example, to trigger the POST request, and of course, this can be also applied in the GET hook as well. We may define the fetch function and return it from our hook and call it when we trigger some action and not when the component renders (useEffect).

Also, we can set a parameter for the headers as well.

Again, the implementation of these 2 custom hooks may be different and improved depending on the developer’s needs. What is worth noticing is the usage of TypeScript and the generic types, mapping system, usage of a custom hook, and the difference between useEffect and useCallback approaches of implementing the hook. Feel free to play around with it.

News Credit

%d bloggers like this: