Controlled vs Uncontrolled Components in React

In this blog, we'll dive deep into controlled vs. uncontrolled components and how these concepts are used while implementing forms.

We can share the state between components in controlled and uncontrolled ways. If the component has some internal state and the parent component does not influence it then the component is called uncontrolled. In contrast, the component is called controlled when important information in it is driven by props rather than its own local state which lets the parent fully specify its behavior.

It is a good practice to keep a single source of truth to share data between components.

Handling inputs in HTML

Before talking about react-controlled and uncontrolled inputs, let's discuss how inputs are manipulated and which technique is used to handle form fields in HTML.

The input element is one of the most powerful and complex in all of HTML due to the sheer number of combinations of input types and attributes.

The value attribute is a string that contains the current value of a text entered into the text field which can be retrieved using the HTMLInputElement value property in javascript.

<input type="text" id="name" name="name" />
let value = document.querySelector("input").value

This technique utilizes uncontrolled form fields as the input value is handled by the DOM itself.

It is considered a best practice to use controlled form fields to manipulate the internal state of an input.

Let's talk about the issue

You might have come across this issue while working with input fields in React.

It is because in HTML, input,textarea and select typically maintain their state and update it based on the user input. In React, these mutable states are typically kept in the state property of the component and only updated with the setter function.

Uncontrolled Input component

We can work with these inputs in an HTML way i.e. in an uncontrolled way.DOM handles the value of an input.

function App(){
const InputRef = React.useRef(null)
return (
<input type="text" name="name" id="name" ref={InputRef} />
)}

We can retrieve the input value using the current.value Property available in the ref.

console.log(InputRef?.current?.value);

It is better to use the ternary operator to check the value as the initial value is null so it'll throw an error.

By using useRef, we have referenced a value of an input element and pulled the value from the field when we needed it.UseRef lets us reference a value that's not needed for rerendering.

Controlled Input component

A controlled input accepts its current value as a prop, as well as a callback to change that value. The input value is always driven by the React State. Let's understand what that means:

<input value={someValue} onChange={handleChange} />
function Form(){
 const [someValue, SetSomeValue] = React.useState("");
return (
      <input
        type="text"
        name="name"
        id="name"
        value={someValue}
        onChange={(e) => {
            SetSomeValue(e.target.value);
        }}
      />
)
}

The form component saves the input value in its internal state.

Everytime a new character is typed, SetSomeValue is called which takes the new value of the input and sets in the state.

This way data(state) and UI(inputs) are always in sync.

In Conclusion

Both Controlled and Uncontrolled form fields have their merits and demerits. You can use them according to your specific situation.

You can read more about them and their use cases in this blog.