Hook Your Fetch Requests With React

From version 16.8, the React team has provided the community with the addition of Hooks.
They let us write functional components and use previously exclusive features of class components, such as state, context and lifecycle callbacks.
Besides that, the React documentation presented us with the possibility to build our own hooks to extract component logic into reusable functions.
Based on this statement, we can identify various situations, in most of our projects, where we can use this powerful feature to make development faster and easier.
Let’s say, for example, you have two or more components that implement common logic. We can create a Hook that implements this logic and use it in all our components, meaning fewer keystrokes and repetitive code.
Among other situations suitable for using Hooks, this article is about when you have to communicate with a REST API to fetch or submit data.
For this, we’ll build an example app that manages a list of tasks needing to be done (the old to-do example).
The Back End
As this article is focused on the front-end side of the application, we’ll use a mock REST API for our back end, mockAPI.io.
It has a free account option that lets you create one project only, but with multiple endpoints. In our case, it’ll fit well, as we only need one endpoint (“tasks”).
The data will have five fields:
ID
createdAt
description
done
(boolean)updatedAt
You can check out the field’s definition in the picture below:

mockAPI provides us with four REST verbs for each resource/collection:
GET
(fetch data)POST
(create new data)PUT
(update data)DELETE
(destroy data)
The GET
verb can be used with or without the ID
parameter, to fetch one specific task or all of them.
Below is a picture I created in mockAPI of the definitions, so you can visualize it better.

The back-end address provided by mockAPI to my application is https://5cfabdcbf26e8c00146d0b0e.mockapi.io/:endpoint
.
:endpoint
is the name of the resource we created (tasks).
So, if you point your browser to the https://5cfabdcbf26e8c00146d0b0e.mockapi.io/tasks
url, you’ll see a list; our list of tasks.
With this part done, let’s head to the fun part of the work, which is:
The Front End
OK, it’s not the most fun part as it’s not what we’re supposed to build yet, but we’ll get there.
Besides that, the easiest way (at least for me) to identify the situations where a hook can be used is by building the application components without having to worry about this.
Our application will be composed of one container (List
) that will be responsible for the state management and to make the fetch requests to our back end.
In this example, we won’t use Axios or another wrapper around HTTP requests; we will use the JavaScript Fetch API.
If you’re unfamiliar with it, you can learn more about it in the MDN web docs.
The other components are all presentational:
Filter
: handles the select-filter control. Receives the filter value andsetFilter
callback from theList
container.NewTask
: handles the text input that creates a newTask
. Receives thenewTask
value andsetNewTask
callback from theList
container.Task
: handles each of the tasks shown in the list. Receives the task itself and callbacks (toogleTask
anddeleteTask
) from theList
container.ActionButtons
: handles the drawing and clicking of each task action button. Receives the task and callbacks (toogleTask
anddeleteTask
) from theTask
component.
You can check out the working application and the complete source code on Codesandox.
It’s simple and straight-forward code. I’m sure that’s not the best way to do it, there’s plenty of space for improvements, but for this article, it’s perfectly fine.
We’ll focus on the container methods that deal with fetching data.
I’ve copied them here, so we can get a clear view of the code repetition that we can get rid of using a hook.
We’ll start with the initialization code that runs inside the useEffect
hook:
It fetches the data from the API, transforms it to JSON, and passes it to other functions to give them the correct treatment.
The same happens with the other methods. I’ll mark the relevant code in bold and italic.
const addTask = () => {
if (!newTask) return;
setLoading(true);
fetch("https://5cfabdcbf26e8c00146d0b0e.mockapi.io/tasks", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
description: newTask,
createdAt: new Date().toISOString(),
done: false,
updatedAt: ""
})
})
.then(resp => resp.json())
.then(data => {
const newList = [...list, data].sort((a, b) =>
a.createdAt < b.createdAt ? 1 : -1
);
setList(newList);
setNewTask("");
setLoading(false);
});
};const toogleTask = task => {
const { id, done } = task;
setLoading(true);
fetch(`https://5cfabdcbf26e8c00146d0b0e.mockapi.io/tasks/${id}`, {
method: "PUT",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
done: !done,
updatedAt: new Date().toISOString()
})
})
.then(resp => resp.json())
.then(data => {
const newList = list
.map(l => {
if (l.id === id) {
l.done = data.done;
l.updatedAt = data.updatedAt;
}
return l;
})
.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));
setList(newList);
setNewTask("");
setLoading(false);
});
};const deleteTask = task => {
const { id } = task;
setLoading(true);
fetch(`https://5cfabdcbf26e8c00146d0b0e.mockapi.io/tasks/${id}`, {
method: "DELETE",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
})
.then(resp => resp.json())
.then(data => {
const newList = list
.filter(l => l.id !== data.id)
.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));
setList(newList);
setLoading(false);
});
};
The only difference we can identify here, is that some Fetch calls have default headers. Others, such as GET
, don’t need it (because the default verb the Fetch API uses is GET
), but it all seems the same.
That’s where we can fit a hook. And that’s what we’ll do right now.
Custom Hooks
As you may already know (or not):
“A custom Hook is a JavaScript function whose name starts with ”
use
” and that may call other Hooks.” (React documentation)
So in the end, custom Hooks can be written as simple JavaScript functions.
In our case, we can think of it as a function that receives the endpoint URL, stores it, and returns an object with the methods we’ll use to make the Fetch calls with different verbs.
And below is the code I came up with:
Straight-forward code, nothing too much complicated. I’ve added a helper function (customFetch
) so I didn’t have to rewrite the whole Fetch command again.
And how do we use that?
The first step is to import the Hook in the List
container.
In my example, I’ve put the useFetch
code inside the src/Hooks
folder:
import useFetch from "../Hooks/useFetch";
The second step is to use the Hook, informing the endpoint URL and attributing it to a constant.
const tasksApi = useFetch(
"https://5cfabdcbf26e8c00146d0b0e.mockapi.io/tasks"
);
With these two lines, we’re all set to use our custom Hook, such as in this addTask
code:
Conclusion
There’s a lot of space for improvement in the Hook, like any other code we see around the web.
One good addition, I think would make sense, is the addition of an HTTP basic authentication that stores the auth token in the state and uses it in all subsequent Fetch headers.
However, that’s a story for another article or maybe an exercise for the readers.
And, of course, if you inspect the code you can identify other places where you can make a custom Hook or a helper function to make the code smaller, such as the array sort part, which is repeated in all four methods (useEffect
, addTask
, deleteTask
, and toogleTask
).
However, this is probably also a subject for another article (or for the comments in this one).
So, I think we’re done here and have accomplished what this article was supposed to achieve.
The working application using the useEffect
Hook we built is available in Codesandbox.
Hopefully, you enjoyed this short article and learned something from it.
Any suggestions or observations are welcome as always.