React Js

7.ReactJS Forms in Detail | Examples with useState, useRef, and React-Hook-Form

ReactJS Forms in Detail

Building forms is one of the most common yet crucial tasks in any web application—and ReactJS provides multiple ways to tackle it. Whether you’re creating a simple contact form or a complex multi-step input system, mastering how forms work in React is essential. In this guide, we’ll explore practical and modern approaches to building forms using React. We’ll start with the classic useState method, move to useRef for direct DOM manipulation, and finish with the powerful react-hook-form library that simplifies validation and state handling.

Through hands-on code examples, you’ll learn how to handle input values, form submission, and validation effectively. Whether you’re a beginner or an intermediate React developer, this tutorial will help you build cleaner and more scalable forms for your next project.For this article’s demo, we’ll look at a few different ways to implement a sign-up form. We will explore how to build forms using useState, useRef, and also a form library like react-hook-form

For this article’s demo, we’ll look at a few different ways to implement a sign-up form. We will explore how to build forms using useState, useRef, and also a form library like react-hook-form.

1. Basic React Form using useState

<import React from "react">

export default function App() {
  const [email, setEmail] = React.useState("");
  const [password, setPassword] = React.useState("");
  const [acceptedTerms, setAcceptedTerms] = React.useState(false);

  const handleSubmit = (event) => {
    console.log(`\nEmail: ${email}\nPassword: ${password}\nAccepted Terms: ${acceptedTerms}`);
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <h1>Create Account</h1>

      <label>Email:
        <input name="email" type="email" value={email} onChange={e => setEmail(e.target.value)} required />
      </label>

      <label>Password:
        <input name="password" type="password" value={password} onChange={e => setPassword(e.target.value)} required />
      </label>

      <label>
        <input name="acceptedTerms" type="checkbox" onChange={e => setAcceptedTerms(e.target.checked)} required />
        I accept the terms of service
      </label>

      <button>Submit</button>
    </form>
  );
}

2. Using Dynamic Keys with useState (Spread Operator)

<import React from "react">

const App = () => {
  const [formData, updateFormData] = React.useState({});

  const handleChange = (e) => {
    updateFormData({
      ...formData,
      [e.target.name]: e.target.value.trim()
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(formData);
  };

  return (
    <>
      <label>Username <input name="username" onChange={handleChange} /></label><br />
      <label>Password <input name="password" onChange={handleChange} /></label><br />
      {JSON.stringify(formData)}
      <button onClick={handleSubmit}>Submit</button>
    </>
  );
};

export default App;

Q: Why do we write [e.target.name] in square brackets?

This is called computed property syntax. It allows us to dynamically set the object key based on the input’s name. This helps reuse one onChange handler for multiple fields.

3. Using useRef for Forms

<import React from "react">

const App = () => {
  const usernameRef = React.useRef();
  const passwordRef = React.useRef();

  const handleSubmit = () => {
    console.log(usernameRef.current.value, passwordRef.current.value);
  };

  return (
    <>
      <label>Username <input ref={usernameRef} /></label><br />
      <label>Password <input ref={passwordRef} /></label><br />
      <button onClick={handleSubmit}>Submit</button>
    </>
  );
};

export default App;

4. Form using react-hook-form

<import React from 'react'>
<import { useForm } from 'react-hook-form'>

export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('firstName', {
        required: 'You must enter First Name',
        minLength: { value: 8, message: 'Minimum 8 characters' }
      })} />
      {errors.firstName && <span>{errors.firstName.message}</span>}

      <input {...register('lastName', { required: true })} />
      {errors.lastName && <span>Last name is required</span>}

      <input {...register('Email', {
        required: 'Please enter email',
        pattern: {
          value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
          message: 'Invalid email address'
        }
      })} />
      {errors.Email && <span>{errors.Email.message}</span>}

      <input type="submit" />
    </form>
  );
}

5. Additional Validated Form Example

<import React from 'react'>
<import { useForm } from 'react-hook-form'>

function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isDirty, isValid },
  } = useForm({ mode: 'onChange' });

  const onSubmit = (data) => console.log('Form Data:', data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>Name:
        <input {...register('name', { required: 'Name is required' })} type="text" />
        {errors.name && <p>{errors.name.message}</p>}
      </label>

      <label>Email:
        <input {...register('email', {
          required: 'Email is required',
          pattern: { value: /^\S+@\S+$/i, message: 'Invalid email' }
        })} type="email" />
        {errors.email && <p>{errors.email.message}</p>}
      </label>

      <label>Age:
        <input {...register('age', {
          required: 'Age is required',
          validate: (value) => value > 0 || 'Must be positive number'
        })} type="number" />
        {errors.age && <p>{errors.age.message}</p>}
      </label>

      <p>Form is {isDirty ? 'dirty' : 'not dirty'}</p>
      <p>Form is {isValid ? 'valid' : 'not valid'}</p>

      <button type="submit" disabled={!isDirty || !isValid}>Submit</button>
    </form>
  );
}

export default MyForm;

Assignments

  • Create a form without using the spread operator with fields like Product Name, Category, Price, etc.
  • Redo the form using spread operator and dynamic state update
  • Finally, build the same form using react-hook-form with validations

Summary

React makes form handling declarative and powerful, especially when combined with hooks like useState, useRef, and third-party tools like react-hook-form. This tutorial demonstrated how to manage form data through individual states, dynamic keys, and references. It also introduced efficient ways to simplify form logic, reuse handlers, and improve validation using libraries.

We discussed best practices for input handling, submitting form data, and tracking form validity. For production-ready apps, using a library like react-hook-form not only reduces boilerplate code but also ensures better performance and cleaner validation flows. As assignments, readers were encouraged to build forms using both basic React techniques and form libraries. Whether you’re building login pages, product submission forms, or dashboards, these techniques will help you create more robust and scalable ReactJS applications.

Leave a Reply

Your email address will not be published. Required fields are marked *