Handling Forms in React

June 4, 2023 (1y ago)

Hey there! So, let me tell you a little story. Once upon a time, I was trying to learn how to handle forms in React. And let me tell you, it was not a walk in the park. I found myself scratching my head and wondering why on earth it was so difficult to understand. But then, after many cups of coffee and some late nights, it finally clicked! And now, I want to share my knowledge with all of you lovely people out there who might be struggling just like I was. So buckle up and get ready for some form-handling fun (yes, that’s a thing)! 😂

Introduction to Forms

In HTML, forms are used to collect user’s input which is generally sent to a server to process. Form can be visualized as a container for all input elements such as : text-fields, radio buttons, checkboxes, etc. You can learn more about forms here For example,

<form>
  <label for="f-name">First name:</label>
  <input type="text" id="f-name" name="f-name">
  <label for="l-name">Last name:</label>  
  <input type="text" id="l-name" name="l-name">
</form>

Need for handling forms?

In HTML, when we submit a form, you will notice that the page refreshes itself.

However, since React stores the form data in state. If we don’t handle forms in React, the default behavior of the form will take place (i.e. it will refresh itself and the current state will be lost). This means that when the form is submitted the data entered by the user in the form will be lost forever.

SpongeBob SquarePants

Handling Forms in React

Now, that we know why Handling Form is so important, let’s get started on how to handle them. In React, we can handle form using two ways :

  • Controlled Components
  • Uncontrolled Components

Let's see how they differ from each other and their working.

Controlled Components

An form whose data is being controlled in such a way that it’s data is stored in the React state using useState() and is updated using setState() which can only be triggered by the user. To create your own controlled component, we need to use the value prop and the onChange prop of the form element. For example ,

import { useState } from "react";
const Form=()=>{
  // To store data in state
  const [data,setData]=useState("") // If you provide a value to the component, it must remain a string throughout its lifetime.

  //To handle Submit
  const handleSubmit=(event)=>{
    event.preventDefault() //Prevents the default behaviour
    alert('You have entered the name: '+ data)
  }

  //To handle change of the input
  const handleChange=(event)=>{
    setData(event.target.value)
    event.preventDefault()  //Prevents the default behaviour
  }
  return(
    <form onSubmit={handleSubmit}>
      <label>
          Name:
          <input type="text" value={data} onChange={handleChange} />
        </label>
        <input type="submit" value="Submit" />
    </form>
  )
}
export default Form;
Handling Multiple Inputs

To handle multiple inputs, you can use name attribute of an input element to access it and let the handler function choose what to do with it.

Note : For checkboxes, use event.target.checked instead of event.target.value Example:

import { useState } from "react";

const Form=()=>{
  const [state,setState]=useState({isGoing: true,numberOfGuests: 2})
  
  const handleInputChange=(event)=>{
    event.preventDefault();
    const target=event.target
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    setState((prevState)=>{
      return {...prevState,[name]:value}
    })
    console.log(state)
  }

  return(
    <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={state.isGoing}
            onChange={handleInputChange} 
            />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={state.numberOfGuests}
            onChange={handleInputChange}
             />
        </label>
      </form>
  )
}
export default Form;

Using controlled components in React can be time-consuming because you have to write an event handler for every change in data. This can be frustrating when converting old code to React or using it with non-React libraries. In these cases, you might want to try uncontrolled components, which are another way to implement forms.

Uncontrolled Components

Even if you manage to create a form which can handle multiple inputs, it still wouldn’t solve the performance issues as the component would re-render after each state update. Therefore, you may use uncontrolled components which makes use of useRef() to get form values from the DOM(Document Object Model). Example :

import { createRef } from "react"

const Form=()=>{
  const input=createRef()

  const handleSubmit=(event)=>{
    event.preventDefault()
    alert('A name was submitted: ' + input.current.value);
  }
  return(
    <form onSubmit={handleSubmit}>
        <label>
          Name:
          <input type="text" ref={input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
  )
}
export default Form

As we can see an uncontrolled component gets the form values from the DOM, and is much more easier to implement as well as much less code than controlled input.

However, it is still advised to use controlled components instead of uncontrolled components.

Conclusion

You can head over to all the Sandbox which I've embedded and try to understand the code more efficiently. Also, I suggest reading some official docs by React.

Farewell, my brave hobbits

LOTR