In web development, especially when using libraries such as ReactJS, you will likely come across terms like “controlled” and “uncontrolled” components.
These terms often confuse beginners, particularly those transitioning from other programming concepts or languages, largely because they are unique to React.
Each component in React has a lifecycle that makes it easy to predict and control how your application functions. These components in React can broadly be categorized into two types: controlled and uncontrolled components.
Controlled Components
A controlled component in ReactJS is a component where React handles the state (data) of the form.
In other words, the form data changes are handled by the React component, hence the term “controlled.”
Here, the state of the form is directly controlled by the component’s state. The form field sets the value property using a state variable and updates that state whenever a user changes the input field’s content.
A key character of controlled components is the tie between form value and state; this means anytime there’s an update in the state, the render method will run, updating the displayed value.
Example of a Controlled Component
// ControlledForm
export const ControlledForm = () => {
const [state, setState] = useState({ value: "" })
function handleChange(e) {
setState({ value: e.target.value })
}
return <input type="text" value={state.value} onChange={handleChange} />
}
Uncontrolled components
On the other hand, there are uncontrolled components that work differently. They maintain their internal state, and you query the DOM using a ref to find its current value when you need it.
This is more like traditional HTML.
Simply put, in uncontrolled components, form data is handled by the DOM itself. The values are pulled from the component at a particular time, usually when the form is submitted. The form values are stored in the DOM, not the component.
Example of an Uncontrolled Component
// Uncontrolled Component
import { useRef } from 'react';
export function UncontrolledForm() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
console.log(this.inputRef.value)
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>
Focus the input and log the value of the input field
</button>
</>
);
}
In the code snippet above, the current.value
of inputRef
refers to the value of the input field at any given time.
Final words
The choice between controlled and uncontrolled components often depends on personal preference and project needs.
Some developers favor controlled components because they appreciate direct control and predictability, while others favor uncontrolled components drawn by the simplicity of keeping the data in the DOM.
However, despite the debates about which is better, it’s safe to say that controlled components are generally recommended in form handling since they allow for more predictable code.
Unpredictability is one of the main sources of bugs in programming and something we should strive to minimize. But in cases where performance becomes an issue and you find that your app re-renders too frequently, uncontrolled components come in handy. In conclusion, understanding these two concepts is integral in mastering ReactJS as they form the backbone for managing forms in any React application.