Appearance
Controlled vs Uncontrolled Components
In React, there are two ways of handling form data input: controlled vs uncontrolled.
Controlled
In a controlled component, we manage the data explicitly either in a local state or reducer.
js
import React, { useState } from 'react';
function Controlled() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<input type="text" value={value} onChange={handleChange} />
);
}Advantages include:
- Single source of truth: Easier to synchronize the UI with a single state.
- Validation: Easy to control the validation of the data.
Disadvantages include:
- Performance: The state is updated by the component on every input.
- Complexity: Loses many built in features on typing the input and would need to manually create a good UX.
Uncontrolled
In an uncontrolled component, the input element manages the data itself and we use ref to get the data implicitly.
js
import React, { useRef } from 'react';
function Uncontrolled() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log(`Submitted value: ${inputRef.current.value}`);
}
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
</form>
);
}Advantages include:
- Less Code: The default built-in input behaviors handle many common data input expectations.
- Performance: Requires fewer rendering of the component.
Disadvantages include:
- Validation: Harder to validate.
- Synchronization: Harder to share data value across different components.
Suggestion
In practice, I would recommend defaulting to uncontrolled input while still storing the state onChange for its simplicity and input standardization:
js
function onChange(e) {
setState(e.target.value)
}
<input onChange={onChange}/>Only switch to controlled input when we need full control over the data of the input.