In React, there are two approaches to handling form data in our components. The first way is by using state within the component to handle the form data. This is referred to as a controlled component. The second way is to let the DOM handle the form data by itself in the component. This is known as an uncontrolled component.
In this post, we shall discuss forms and explain React's difference between controlled and uncontrolled components.
First: Controlled Components
In a controlled component, form data is handled by the component's state. The data is held by HTML form elements such as <input>
, <textarea>
, and <select>
which typically maintain their own state and update it based on user input.
With a controlled component, the input’s value is always driven by the React state. While this means you have to type a bit more boilerplate code, you can now pass the value to other UI elements too, or reset it from other event handlers.
In React we can use state in our component to hold or manage the values of the elements in a form element. Here’s an example that logs the firstName and lastName when it is submitted:
import React from 'react'
export default function Form(){
const [formData, setFormData] = React.useState(
{
firstName: "",
lastName: "",
}
)
function handleChange(event){
const {name, value} = event.target
setFormData(prevFormData => {
return {
...prevFormData,
[name]: value,
}
})
}
return (
<form>
<label>
FirstName:
<input type="text" name="firstName" placeholder="First Name" onChange={handleChange} value={formData.firstName}/>
</label>
<label>
LastName:
<input type="text" name="lastName" placeholder="Last Name" onChange={handleChange} value={formData.lastName}/>
</label>
</form>
)
}
Note 💡- Remember to add Console.log(formData)
just before our handleChange function.
The formData state holds the value of the firstName and lastName input element. When a value is being typed in the firstName and lastName input element, the onChange event attached to it sets the value of the input to the formData state using the onChange function.
As you can see, the values of our input elements firstName and lastName are controlled by the React state; the state becomes the “single source of truth” for the input elements. Therefore, the Form component shown above is a controlled component.
The drawback to using controlled components is that the number of states in a component increases as more control elements are added to the form element.
Second: Uncontrolled Components
The alternative is uncontrolled components, where form data is handled by the DOM itself. “Uncontrolled” refers to the fact that these components are not controlled by React state.
You can use a ref to get the form values from the DOM. For example, this code accepts a single name in an uncontrolled component:
class Form extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Note💡 - You can interact with this Codepen here which you might find useful.
Since an uncontrolled component keeps the source of truth in the DOM, it is sometimes easier to integrate React and non-React code when using uncontrolled components. It can also be slightly less code if you want to be quick and dirty. There are valid cases for using uncontrolled components in the real world especially for simple forms and when learning React. It's just not as powerful though so you should usually use controlled components.
If it’s still not clear which type of component you should use for a particular situation, you might find this article on controlled versus uncontrolled inputs to be helpful.
Conclusion
The question is not whether controlled are uncontrolled components are better, but which better serves your use case and fits your personal preference.
If you click through the React documentation on Uncontrolled Components you get to this table:
Feature | Uncontrolled | Controlled |
---|---|---|
one-time value retrieval (e.g. on submit) | ✅ | ✅ |
validating on submit | ✅ | ✅ |
Instant field validation | ❌ | ✅ |
conditionally disabling submit button | ❌ | ✅ |
Enforcing input format | ❌ | ✅ |
several inputs for one piece of data | ❌ | ✅ |
dynamic inputs | ❌ | ✅ |
You want to pick the right tool that will make your life easier.