How To Create a Custom Hook to Handle Inputs in React
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
- The Custom Hook
- Creating the Form Component
- Creating the
useInput
Hook - Applying the Input Logic
- 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.
We proceed to style with tailwind CSS as shown below:
The result of this styling, as displayed on the browser, is more like it.
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 theenteredValue
state when the value of the input field changes. It is used as aonChange
handler for the input field.inputBlurHandler
: This function sets theisTouched
state totrue
when the input field is blurred, that is, when the input has lost focus after being interacted with. It is used as aonBlur
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.