ReactJS: Controlled vs Uncontrolled components

One powerful concept provided by React is the use of controlled components. Forms are commonly used in web pages, and controlled components are the recommended standard when implementing forms using React.

Uncontrolled Components

In traditional HTML forms, the components such as <input> typically maintain their own state and update it based on user input. In other words, they will accept what we type and have the responsibility of remembering it, and in order to retrieve the values they remembered, you have to “pull” it when you need it. The latter usually happens during form submission. They can be classified under uncontrolled components.

This can also be applied using React, as shown by the example snippet below, which basically accepts a single name in an uncontrolled component scenario:

class NameForm extends React.Component {
 constructor(props) {
   super(props);
   this.handleSubmit = this.handleSubmit.bind(this);
 }

 handleSubmit(event) {
   alert('A name was submitted: ' + this.input.value);
   event.preventDefault();
 }

 render() {
   return (
     <form onSubmit={this.handleSubmit}>
       <label>
         Name:
         <input type="text" ref={(input) => this.input = input} />
       </label>
       <input type="submit" value="Submit" />
     </form>
   );
 }
}

To create an uncontrolled component in React, we can use a ref to get the values. Here we can see that the value in the <input> element is stored in itself, and the value will only be passed when the form is submitted, which triggers the handleSubmit function in the form element’s onSubmit attribute. The handleSubmit can typically perform any procedure such as sending the value through an API, but in this case, it will only display an alert with the value from the uncontrolled component.

Controlled Components

On the other hand, controlled components will still accept what we type but will not be held responsible for keeping it in mind. Instead, the component has what is called a “callback function” that is triggered each time we enter something new in the form element. Triggering the function will typically store or update what we type in the same React component that displays the form element that was used (therefore outside the form element that we are typing on,) and then updating the value displayed on the form element to match we inputted and what is now stored in the React component.

Using the previous example, we can modify it to implement controlled components:

class NameForm extends React.Component {
 constructor(props) {
   super(props);
   this.state = {value: ''};

   this.handleChange = this.handleChange.bind(this);
   this.handleSubmit = this.handleSubmit.bind(this);
 }

 handleChange(event) {
   this.setState({value: event.target.value});
 }

 handleSubmit(event) {
   alert('A name was submitted: ' + this.state.value);
   event.preventDefault();
 }

 render() {
   return (
     <form onSubmit={this.handleSubmit}>
       <label>
         Name:
         <input type="text" value={this.state.value} onChange={this.handleChange} />
       </label>
       <input type="submit" value="Submit" />
     </form>
   );
 }
}

In this case, there is still a submit button but the <input> component is now “controlled”. Basically, a form element is controlled if its value is set using a prop. The <input> component now has a “callback function” handleChange declared in the attribute onChange, which is triggered when we type an input. The function handleChange is then responsible for setting the new value of the input by using setState to change value. Changing the value also updates the value attribute in the <input> element.

Conclusion

Controlled components are a convenient and powerful approach of implementing forms the “React way,” but it isn’t necessarily the best way in general. It still depends on the approach or situation that you are aiming to to achieve or resolve.

If you only need to create a form which will be very simple, let’s say for example it only requires a user to input his first and last name, then an uncontrolled component implementation should be good enough. You will just probably need to just retrieve and validate the values during form submission anyways.

But if you aim to have automatic field validations, disabling the submit button if ever there’s an invalid input, or even dynamic inputs for your form, then you might consider using controlled components using React. Additionally, if ever you start your application with uncontrolled components, it isn’t that hard to migrate to controlled components.

Primary image is taken from ReactJS Official Website

Blog Posts by Jihad Talic


Related Entries