# Mastering Form Management with React useForm Plugin Library

Introduction:

Managing forms in web applications can be a complex task, especially when dealing with validation rules, error handling, and form submissions. The React `useForm` plugin library offers a powerful and elegant solution to simplify form management in React applications. In this tutorial, we will walk through a comprehensive example of using the `useForm` library to handle form lifecycle events, such as validations, rules, and form submissions. By the end of this tutorial, you will have a solid understanding of how to use the React `useForm` plugin library to efficiently manage forms in your React applications.

Prerequisites:

* Basic understanding of JavaScript and React
    
* Familiarity with React functional components and hooks
    
* Knowledge of form validation and handling in web applications
    

Getting Started:

To begin, let's install the React `useForm` plugin library by running the following command:

```javascript
npm install react-hook-form
```

Now that we have the library installed, let's dive into a practical example of using the `useForm` library to manage a form lifecycle.

Example: Create and Update Client Action Items

In this example, we will create a form to create and update client action items. The form will include fields for `title`, `category`, `description`, and `target_date`. We will use the `useForm` library to manage form state, handle validations, and submit the form data to an API.

Full Code Example;

```javascript
import { useForm } from 'react-hook-form';

export default function CreateClientActionItem({item}) {
    const {
        register,
        handleSubmit,
        formState: {
            errors
        }
    } = useForm({
        defaultValues: {
            title: item?.title ?? '',
            category: item?.category ?? '',
            description: item?.description ?? '',
            target_date: item?.target_date ?? '',
        }
    });

    const onSubmit = (data) => {
        let url = '/test/store-url';
        axios.post(url, data).then((res) => {
            if (res.data.status === 'success') {
                alert("Success");
            } else {
                alert("Error");
            }
        }).catch((err) => {
            notifyError("Unknown error occurred while creating action item")
        });
    }

    const onUpdate = (data) => {
        let url = '/test/update-url';
        axios.put(url, data).then((res) => {
            if (res.data.status === 'success') {
                alert("Success");
            } else {
                alert("Error");
            }
        }).catch((err) => {
            notifyError("Unknown error occurred while updating action item")
        });
    }

    const onError = (data) => {
        console.log(data);
    }

    return <form onSubmit={handleSubmit((item == null) ? onSubmit : onUpdate, onError)}>
            <div
                className="flex flex-col gap-[24px] rounded-[5px] w-full">
                <div className="flex flex-col gap-[16px]">
                    <div className="flex flex-col gap-[16px]">
                        <label htmlFor="title">Title</label>
                        <input type="text" {...register('title', {
                            required: "Title is required",
                            minLength: {
                                value: 2,
                                message: "Title must be at least 2 characters"
                            },
                            maxLength: {
                                value: 50,
                                message: 'Title can be maximum 50 characters'
                            }
                        })} name="title" id="title"
                               className="w-full p-[10px] border border-gray-500 rounded-[5px] pl-10 pr-12 f-16-400-g-sans"
                               placeholder="Title"/>
                        {errors.title ?
                            <p className="text-red-500">{errors.title.message}</p> : null}
                    </div>
                    <div className="flex flex-col gap-[16px]">
                        <label htmlFor="category">Category (optional)</label>
                        <input type="text" {...register('category', {
                            minLength: {
                                value: 2,
                                message: "Category must be at least 2 characters"
                            },
                            maxLength: {
                                value: 50,
                                message: 'Category can be maximum 50 characters'
                            }
                        })} name="category" id="category"
                               className="w-full p-[10px] border border-gray-500 rounded-[5px] pl-10 pr-12 f-16-400-g-sans"
                               placeholder="Category"/>
                        {errors.category ?
                            <p className="text-red-500">{errors.category.message}</p> : null}
                    </div>
                    <div className="flex flex-col gap-[16px]">
                        <label htmlFor="description">Description</label>
                        <textarea {...register('description', {
                            required: "Description is required",
                            minLength: {
                                value: 2,
                                message: "Description must be at least 2 characters"
                            },
                        })} name="description" id="description"
                                  className="w-full p-[10px] border border-gray-500 rounded-[5px] pl-10 pr-12 f-16-400-g-sans"
                                  placeholder="Description"/>
                        {errors.description ?
                            <p className="text-red-500">{errors.description.message}</p> : null}
                    </div>
                    <div className="flex flex-col gap-[16px]">
                        <label htmlFor="target_date">Target date (optional)</label>
                        <input type="date" {...register('target_date')} name="target_date"
                               id="target_date"
                               className="w-full p-[10px] border border-gray-500 rounded-[5px] pl-10 pr-12 f-16-400-g-sans"
                               placeholder="Description"/>
                    </div>
                </div>
                <div className="flex flex-row items-center gap-[40px]">
                    <button type="submit" className="primary-button bg-defaultPrimary">{!item ? 'Create action item' : 'Update action item'}</button>
                    <h1 onClick={closeHandler} className="text-defaultPrimary cursor-pointer">Cancel</h1>
                </div>
            </div>
        </form>
}
```

Code Explanation:

**1\. Import** `useForm`**:**

Start by importing the `useForm` hook from the library:

```javascript
import { useForm } from 'react-hook-form';
```

**2\. Initialize** `useForm`**:**

In the `CreateClientActionItem` functional component, initialize the `useForm` hook and destructure its returned properties:

```javascript
const {
    register,
    handleSubmit,
    formState: {
        errors
    }
} = useForm({
    defaultValues: {
        title: item?.title ?? '',
        category: item?.category ?? '',
        description: item?.description ?? '',
        target_date: item?.target_date ?? '',
    }
});
```

The `defaultValues` option allows you to set initial values for the form fields.

In this example, we use the optional chaining operator “`?”` and the nullish coalescing operator “`??”` to set the default values to empty strings if `item` is not provided.

**3\. Register form fields:**

To register form fields with the `useForm` hook, use the `register` function provided by the hook. The `register` function takes two arguments: the field name and an optional configuration object. The configuration object can include validation rules, such as `required`, `minLength`, and `maxLength`. If a validation rule fails, an error message is provided and stored in the `errors` object.

For example, registering the `title` field with validation rules:

```javascript
<input type="text" {...register('title', {
    required: "Title is required",
    minLength: {
        value: 2,
        message: "Title must be at least 2 characters"
    },
    maxLength: {
        value: 50,
        message: 'Title can be maximum 50 characters'
    }
})} ... />
```

Similarly, register the `category`, `description`, and `target_date` fields with appropriate validation rules.

**4\. Handle form submission:**

The `handleSubmit` function is used to manage form submissions. It takes two arguments: a function to be executed on a successful submission and a function to be executed if there are any errors.

In our example, we use the `onSubmit` function for creating a new action item and the `onUpdate` function for updating an existing one:

```javascript
<form onSubmit={handleSubmit((item == null) ? onSubmit : onUpdate, onError)}>
```

The ternary operator checks if `item` is `null`, which indicates a new action item should be created. If `item` is not `null`, it means we are updating an existing action item.

**\- Display error messages:**

If there are any validation errors, they are stored in the `errors` object. To display error messages, check if an error exists for a specific form field and render the error message accordingly:

```javascript
{errors.title ?
    <p className="text-red-500">{errors.title.message}</p> : null}
```

In this example, if there is an error for the `title` field, the error message is displayed in a paragraph element with a `text-red-500` class. Similarly, error messages are displayed for other fields such as `category` and `description`.

**\- Form submission logic:**

In the `onSubmit` and `onUpdate` functions, we use the `axios` library to send HTTP requests to the API for creating or updating an action item.

The response is checked for the `status` property to determine if the request was successful.

If successful, we display a success notification, update the item, and close the form. If unsuccessful, we display an error notification:

```javascript
axios.post(url, data).then((res) => {
    if (res.data.status === 'success') {
        alert('success');
    } else {
        alert('error');
    }
}).catch((err) => {
    notifyError("Unknown error occurred while creating action item")
});
```

In the `onError` function, we log the error data to the console. In a real-world scenario, you might want to handle the errors differently, such as by displaying a user-friendly error message.

**Conclusion:**

In this tutorial, we have explored how to use the React `useForm` plugin library to handle form lifecycle events, including validations, rules, and form submissions.

By using this powerful library, you can streamline form management in your React applications and build robust, user-friendly forms with ease.

The provided code example demonstrates a practical use case that can be adapted to suit your specific requirements. With this knowledge, you can now confidently tackle form management challenges in your React projects.

Happy coding!
