DEV Community

Andrew Simmons
Andrew Simmons

Posted on

Making a Custom Hook

Introduction to Hooks

Hooks were released in React 16.8, you've probably become familiar with the useState and useEffect hook using them to keep track of state or do some basic actions in your web app like making a 'GET' request. But there are actually a lot more opportunities for us to use hooks, because we can make our own.

As programmers we always try to make our code DRYer, and hooks are an excellent tool that can help us do this. Think of an action that you have to do various times in various components, a couple of examples come to my mind: Making a form or making a request to the server. These would both make great custom hooks that we could use to help DRY up our code. In this post, I'll be teaching you how to make a custom hook for all of the forms in your project.

Looking at the original code

When you go to make your custom hook, first look at the original code that the hook will be replacing:

const NewReview = ( {airline, currentUser} ) => {
  const [form, setForm] = useState({
      title:"",
      score:1,
      content:""
    })

  const handleChange = e => {
    setForm({
      ...form,
      [e.target.name]:e.target.value
    })
  }

return (
<form onSubmit={handleSubmit}>
        <input type="text" name="title" value={form.title} onChange={handleChange} placeholder="Title"/><br/>
        <input type="text" name="score" value={form.score} onChange={handleChange} placeholder="Score"/><br/>
        <input type="text" name="content" value={form.content} onChange={handleChange} placeholder="Score comments"/><br/>
        <input type="submit" placeholder="Submit"/>
      </form>
)
Enter fullscreen mode Exit fullscreen mode

That is one example, and if I look at other examples, I see a pattern that all of my forms have an initial state, and then a handleChange function to keep the state and the input fields reflecting the same value.

Great! Now that we have an idea of what our hook will include, let's get started!

Making the Hook

You can organize your code how you like, but I would recommend putting all of your custom hooks in one place, I'm going to have a folder under src labeled hooks.

One important thing to remember is that hooks have a very specific naming convention that you have to follow otherwise react won't know that you've made a hook. All hooks must start with the word 'use'. That's why the 'useState' and 'useEffect' are named as they are. So for our form hook we could have names use as 'useForm', 'useInput', or 'useMyCustomFormMakerHook'. But I like to keep it simple, so we'll go with 'useForm' for ours.

import React, {useState} from 'react'

export const useForm = (initialForm) => {

  return 
}

Enter fullscreen mode Exit fullscreen mode

You can also use other hooks to make your custom hook, so we've imported useState. Any input that you want for the hook to recieve, you place it as an argument like we've done above as initialForm.

Now in our original hook, we had two main parts, we had our state that we used for our values in the form and we have a function that we called handle change. So let's add that in from our original code:

import React, {useState} from 'react'

export const useForm = (initialForm) => {
const [form, setForm] = useState(initialForm)

  const handleChange = e => {
    setForm(
      {...form,
      [e.target.name]:e.target.value}
      )
      // console.log(e.key)
  }
  return 
}

Enter fullscreen mode Exit fullscreen mode

There that looks great! Now our last step to complete our hook, is to think about what we want to return. I always think about the useState hook and how it returns a variable and a function because that's exactly what we're doing here, and we can make it look like the original useState by returning them in an array like so:

import React, {useState} from 'react'

export const useForm = (initialForm) => {
const [form, setForm] = useState(initialForm)

  const handleChange = e => {
    setForm(
      {...form,
      [e.target.name]:e.target.value}
      )
  }
  return [form, handleChange]
}

Enter fullscreen mode Exit fullscreen mode

Alright let's try this new hook out in the wild by replacing our previous code with the hook:

import { useForm } from "../hooks/useForm"

const NewReview = ( {airline, currentUser} ) => {
  const [form, handleForm] = useForm({
      title:"",
      score:1,
      content:""
    })

return (
<form onSubmit={handleSubmit}>
        <input type="text" name="title" value={form.title} onChange={handleChange} placeholder="Title"/><br/>
        <input type="text" name="score" value={form.score} onChange={handleChange} placeholder="Score"/><br/>
        <input type="text" name="content" value={form.content} onChange={handleChange} placeholder="Score comments"/><br/>
        <input type="submit" placeholder="Submit"/>
      </form>
)
Enter fullscreen mode Exit fullscreen mode

And there we go! We've just made a custom hook to make our code DRYer. This hook currently only works for text type inputs, but it's easy enough to put in a conditional to check for other types as well. Give it a try! Now see if you can make your own custom hook for a basic get request!

For more information on custom hooks, checkout the React docs here

Top comments (0)