• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/3/22

Take Hooks to the Next Level

If you took the first course, you learned about hooks through  useState  and  useEffect  . In this course, you saw how to use these hooks to make API calls. And in the last chapter, you discovered context and how to easily access it with  useContext  . You now have quite a few tricks up your sleeve when it comes to using hooks in your React applications. 🎉

Ready to create your own hooks? You can do it!

Create Your Own Hooks to Simplify Code 

I don’t know about you, but the first time someone told me I could make my own hooks, I panicked slightly. I imagined working on the React codebase and creating an enormous file to run a custom hook.

Don't worry; it’s easy to create a custom hook: it’s simply a function that starts with “use,” which extracts the reusable logic and can use other hooks. 

Let’s see how this works in practice.

Create a Hook for Your API Calls 

In chapter 1, you called the API for the Shiny project to get freelancer profiles and the questions for a survey.

Take a closer look at your code. Can you see some repetition? That’s totally normal – we’re going to try to pool all of that with a custom hook!

To do this, create a new file in  /utils  and call it  /hooks . Then create an  index.jsx  file.

For creating the hook, use the syntax  async / await  :

import { useState, useEffect } from 'react'

export function useFetch(url) {

const [data, setData] = useState({})

const [isLoading, setLoading] = useState(true)

useEffect(() => {

if (!url) return

async function fetchData() {

const response = await fetch(url)

const data = await response.json()

setData(data)

setLoading(false)

}

setLoading(true)

fetchData()

}, [url])

return { isLoading, data }

}

The code’s quite clear, isn’t it? For the new  useFetch  hook, pass the URL of the API you want to call as a parameter. It has an internal state that lets it store data and know if data is loading with  isLoading  .

In  useEffect  , the hook carries out an empty  return  if the URL parameter is empty, and starts by setting  isLoading  to  true  . It declares the asynchronous function  fetchData  in order to:

  • Call  fetch  .

  • Parse what is returned with  data.json() .

  • Change the state of  isLoading  .

url  is part of the  useEffect  list of dependencies, which triggers the call if the URL passed as a parameter change. Then, call the function  fetchData  .

To use the new hook, modify  /Survey/index.jsx  . Start by importing your hook with: 

import { useFetch } from '../utils/hooks'

Then get the data with:

const { data, isLoading } = useFetch(`http://localhost:8000/survey`)

const { surveyData } = data

You should also delete all of the content in  useEffect  that would have performed the fetch . Deleting unnecessary code is incredibly satisfying, don’t you think? 😍

Don’t forget to replace  isDataLoading  with  isLoading  , which will be more generic here, and replace  surveyData  with  data  .

Does it still work?

Uh oh. There’s an error that is stopping the code from running! 😭

It’s nothing to worry about! With navigation, we accessed the content of the question object with  data[questionNumber]  . Except during set up,  data  is an empty object, which means that with:

const { surveyData } = data

surveyData  is undefined. Therefore, JavaScript generates an error for  data[questionNumber]  . One way of avoiding the error is to check that   surveyData  is defined before using it in the component:

<QuestionContent>

{surveyData && surveyData[questionNumber]}

</QuestionContent>

The page once again works like before using the  useFetch  hook, which means a lot of repetitive code was deleted! 🎉

Add Error Handling

But what happens when the API returns an error? The app won’t behave the way you want it to, and your user won’t have any idea what’s going on. It’s a good idea to integrate error handling in the  useFetch  hook so that any problem appears on the screen.

To do this, create a state for  error  in  utils/hooks/index.jsx  with:

const [error, setError] = useState(false)

Then add a try  and a catch to the  useFetch  hook:

export function useFetch(url) {

const [data, setData] = useState({})

const [isLoading, setLoading] = useState(true)

const [error, setError] = useState(false)

useEffect(() => {

if (!url) return

setLoading(true)

async function fetchData() {

try {

const response = await fetch(url)

const data = await response.json()

setData(data)

} catch (err) {

console.log(gerr)

setError(true)

} finally {

setLoading(false)

}

}

fetchData()

}, [url])

return { isLoading, data, error }

}

That lets you pass  error  to  true  whenever you run into a problem.

Similarly, in  Survey.jsx  , you  now get error:

const { data, isLoading, error } = useFetch(`http://localhost:8000/survey`)

And you can just add the following above the return:

if (error) {

return <span>There is a problem</span>

}

Brilliant! You’re even able to handle API call errors! 🎉

With this knowledge in hand, use  useFetch  to send user responses and get the API results from the  /results  page.

Watch how to do all of this in the screencast below. 👇

Will I be able to use  useFetch  in all of my codebases in production?

This  useFetch  hook is excellent for avoiding repetition and practicing how to create custom hooks. However, in reality, this code is a little too basic to be used in production. Instead, you could use a much more robust tool such as React Query, which will let you use hooks to make queries and cache them in your applications.

Handle Hooks With Confidence

Stick to the Rules

A quick reminder: hooks have their own set of rules.

  • Hooks are only accessible in a React function component, meaning that it is not possible to use them in a class component or a simple JavaScript function. 

  • Call hooks at the level of your component root.

  • Be careful when naming your custom hooks. Even if this is a convention rather than a strict rule, your custom hooks should start with  use  so you can immediately identify them. 

For now, here are a few hooks that you’re likely to come across in different codebases:

useRef

Read the documentation if you're interested. Although the  useRef  hook has several uses, it’s mainly used for interacting with DOM elements.

useReducer

useReducer  lets you better manage your state when it includes lots of properties that require periodic modification.

useMemo  and  useCallback

These two hooks allow you to avoid redoing calculations that might impact performance. You can specify the values for which you need to redo calculations only if one of the parameters changes, thanks to  useMemo  and  useCallback  .

And there are more! React is currently on version 17 (at the time this course was written). However, they could have created newer hooks in the meantime.

Give It a Go!

Now that you’ve created your custom hook for making API calls,  useFetch  , you can use it for the  /Freelancers  and  /Results  pages.

You’ll also have to create a personalized  useTheme  hook that gets the context from the theme  and lets you get the current theme ( dark  or  light ).

From there, you can integrate the style changes for the theme and then integrate the  /results  page as per the prototypes if you want to challenge yourself (or get the CSS from the solution branch if you’d prefer to spend less time on the CSS). 

As usual, you’ll find the exercise on branch P2C3-begin and the solution on P2C3-solution.

Let’s Recap!

  • A custom hook is a function that starts with  use  , extracts the reusable logic, and  can use other hooks.

  • The rules of hooks also apply to custom hooks, as does the convention of naming your custom hook  use  ...    .

  • Other hooks exist such as  useRef  ,  useReducer  ,  useMemo  , etc.

Your app is starting to look pretty good! I hope that you’ve enjoyed taking a closer look at hooks. But how can you be sure that you’re not going to break everything if you make changes in 6 months, or even a year, when you no longer remember how your code is implemented? Through tests, of course, which is the topic of the next part. But before moving on, it’s time to test your knowledge with a quiz. Best of luck, and see you in a bit! 💪

Example of certificate of achievement
Example of certificate of achievement