This video is available to students only

Our First Custom Hook: useDepartments

We'll write our first custom hook to fetch department info for our application in one centralized place.

Custom hooks may sound intimidating at first, but useDepartments should change your mind#

If you look through our code, one thing you might notice while checking out the various components is that there are duplicate API calls happening: multiple components call the same API endpoints in our app to retrieve information.

Situations like this are a perfect opportunity to refactor some code into a custom hook and simplify the code contained in our components in the process.

In this lesson, we'll make our first custom hook. We'll learn how to extract code from one component and recreate it in a centralized and reusable hook.

Just like with our previous module lessons, we'll start with a simpler custom hook and work our way up to the more complex ones in future lessons.

Sample code zip file

If you need a copy of the sample app before we begin adding custom hooks, you can download it here.

We make duplicate calls to the department API#

The first duplicate API call that stood out to me is the getAllDepartments call. It's called in both the <ProductList> and the <ProductForm> components after our updates to these components in the last module.

This seems like as good a place to start as any — let's make this call into a custom hook that we can share with all the components that need it.

Create a new hooks folder#

To keep our project organized, let's make a new folder inside the client/src folder named hooks/.

This is where we'll hold all the shared React Custom Hooks that our app will utilize.

Make a new useDepartments.js file#

Once the hooks/ folder exists, we can create a new file inside of it called useDepartments.js.

Following the "Rules of Hooks", which we covered in the module introducing hooks, we name all custom hook files by starting with the word useXyz.js, and since this hook is about fetching departments, we'll name it useDepartments.js.

Okay, we're ready to start adding code to this hook now.

Review the code currently fetching departments#

As I said before, there are two components in our app that are calling the department API: the <ProductForm> and the <ProductList> components.

The useEffect in <ProductForm> calling the getAllDepartments API call currently looks like this.

And the useEffect in <ProductList> calling the same API endpoint currently looks like this.

First, a snapshot of the component's state (this one has quite a few more state variables):

And the actual useEffect fetching the departments.

There are some differences between these two components, but not so many we can't make a hook that can work for both situations. We'll just take it step by step.

Compose the hook#

Looking at the code above, we can see both API calls have a few state variables in common, in addition to the API call itself: they both share the departments and error state variables.

So let's define our hook function, import the useState Hook into our file, and add those two state variables inside of it.

So far, so good.

Move the fetchDepartments function into the hook#

After that, the next piece of code to add is the fetchDepartments call inside of the useEffect Hook.

You can lift and shift the entire useEffect out of the existing <ProductForm> with almost no changes and paste it into the hook.

Pop this code into the hook underneath where we just defined the variables. That code should look like this inside of useDepartments.js:

Okay, we're making good progress.

Remove setLoading and return departments and errors from the hook#

The next thing we're going to need to do is remove the setLoading state in this function. When you look at the two components calling the department API, both have a loading variable that displays some sort of loading spinner until the data's been fetched and transformed.

Once the data's returned, the loader state is set to false, which allows the component to render with the data it retrieves (or the error message it displays if it's failed).

Now, you may be thinking, "Why don't we just declare a loading state variable inside of this hook as well?" We could. That could work, but in each component, that same loading state is used in multiple places inside the component — not just for this API call.

In this case, it makes more sense to remove the setLoading variable from this hook and let the loading state be handled in the components themselves.

Start a new discussion. All notification go to the author.