How To Create a Custom Hook to Handle Inputs in React

OJEBIYI FULNESS
6 min readOct 29, 2023

--

A snippet of the useInput Hook. Created on Ray.so by the author.

Introduction

A common challenge for frontend developers is handling inputs and form validation. You have to set a lot of conditions to fulfil if you want solid validation logic.

Quite rightly, there are a few tools that are help in handling forms, such as Formik, and React Hook Form, among others. If there’s a situation that comes up in which you are unable to use any of these tools and you’re to create forms, this would pose a challenge.

This article will teach you how to create a custom hook to handle any input and, by extension, forms in general. We’ll be creating a signup form to collect details about the email, username, and password of users.

Table of Contents

  1. The Custom Hook
  2. Creating the Form Component
  3. Creating the useInput Hook
  4. Applying the Input Logic
  5. Conclusion

The Custom Hook

The useInput hook is designed to be used in a React component to easily manage the state and behaviour of input fields, including validation and error handling.

Creating the Form Component

The Signup component is defined to create the signup form. We’ll create the form component using the form element and inputs, as shown below:

This will be displayed in the browser, as shown below. Notice that the background colour has been set to gray for better visualization.

Signup form without styling

We proceed to style with tailwind CSS as shown below:

The result of this styling, as displayed on the browser, is more like it.

Signup form with styling.

Now, we have our beautiful signup form. Nice? It sure is!

Creating the useInput Hook

To create the logic for the useInput hook, you need to understand the behaviour of input components.

Usually, when collecting information from inputs, you want to store the value of the inputs and handle errors. To handle errors, you would want to flag an error message if any of the inputs are empty on submission or if the requirements for a valid input are not met.

With these established guidelines, we can proceed to create the useInput hook.

The code below contains the logic for the useInput hook and it will be explained subsequently.

Initialization

First, we import { useState } from "react"

This imports the useState hook from the React library to manage the state and behaviour of input fields in our React component. Then, we create the useInput function.

The useInput hook has a function, validateValue as a parameter. This parameter enables us to validate the input and check for errors.

State Management

When handling the inputs, we need stage management logic to help us determine what to do when the states of the inputs have changed. We are managing two pieces of state here. They are:

  • enteredValue: This state variable stores the current value of the input field.
  • isTouched: This state variable is a boolean flag that indicates whether the input field has been touched (i.e., focused and then blurred).

Validation Logic

Next, we have the validation logic. The valueIsValid variable is used to determine whether the input value is valid based on our validation logic. It is activated by calling the validateValue function with the current enteredValue.

Error Handling

Next, we have error handling. The hasError variable is a boolean that is true when the value is not valid (!valueIsValid) and the input field has been touched (when isTouched is true). The hasError variable is used to determine if an error message should be displayed for the input.

Event Handling

Next, we have the event handlers. Event handlers are functions that respond to specific events triggered by user interactions or other sources. These handlers define how an application should react to these events.

We have three event handlers here:

  • valueChangeHandler: This function is used to update the enteredValue state when the value of the input field changes. It is used as a onChange handler for the input field.
  • inputBlurHandler: This function sets the isTouched state to true when the input field is blurred, that is, when the input has lost focus after being interacted with. It is used as a onBlur handler.
  • inputReset: This function is used to reset the input field's value and touch status to their initial states—empty and untouched.

Passing Functions

Finally, we have a return statement that returns an object, which specifies the values that the function should return. These values include:

  • value : enteredValue The current value of the input field.
  • isValid : valueIsValid: A boolean indicating whether the current input value is valid.
  • hasError: A boolean indicating whether the input value meets the conditions for flagging an error.
  • valueChangeHandler: A function to handle changes in the input value.
  • inputBlurHandler: A function to handle the blur event on the input field.
  • inputReset: A function to reset the input value and touch status.

This is the logic for the useInput hook. We can now proceed to apply this to our signup form.

Applying the Input Logic

Coming back to our form, we can add the logic for input validation.

In the code snippet below, we assign values to the input fields and bind event handlers to them to handle event triggers.

After doing this, we can use the useInput hook to handle the validation.

The component uses the useInput custom hook for three input fields: email, username, and password. For each input field, the component extracts the state and functions returned by useInput.

Validation

The component checks for validity with the formIsValid variable and sets it to true only when all three input fields are valid.

Submission Handling

The code snippet if (!formIsValid) { return; } is used in the formSubmitHandler function to prevent the form from being submitted if formIsValid is false. If the form is valid, the formSubmitHandler function resets the input fields.

The form is prevented from reloading the page on submission with event.preventDefault(). The “Create Account” button is disabled if the form is not valid.

Error Handling

If emailInputHasError is true, it means there is an error with the email input. In this case, emailInput is assigned the value !valid.

If emailInputHasError is false, it means there is no error with the email input, and emailInput is assigned the value valid. The same goes for usernameInputHasError and passwordInputHasError

Now, this is very good logic, but, it’s lacking one thing. We want to display an error message when any of the error conditions are met. To do this, we assign some values for error messages, as shown below:

The regex, short for regular expressions, uses the encoding assigned to it to validate email addresses. We also define error messages for the email, username, and password fields in the variables emailContent, nameContent, and passwordContent

We also define three validation functions (emailCheck, nameCheck, and passwordCheck) for each of the three fields. These functions validate the corresponding form fields based on the provided regular expressions and error messages. If the input is valid, the function returns the value; otherwise, it sets the error message in a variable.

We use conditional rendering to display error messages when an input field is invalid.

You can test the form behaviour in the code sandbox below:

Conclusion

Having a custom hook for handling inputs makes it easier for developers to handle errors. It also keeps the code neat and structured.

Knowing how to build this custom hook will help you as a developer to handle errors in a structured way without having to rely on any external tool or component.

--

--

OJEBIYI FULNESS

Hi! I'm Fulness. I am a frontend developer and technical writer. I love to simplify concepts in frontend development.