Controlled and Uncontrolled Components
One of the strengths of React is its extensibility model, enabled by a common practice of pushing component state
as high up the component hierarchy as appropriate. For simple components (like an input) this
is usually a matter of tying the input value
prop to a parent state property via its onChange
handler.
here is an extremely common pattern:
function MyInput() { const [value, setValue] = useState(''); return ( <input type="text" value={value} onChange={e => setValue(e.target.value)} /> );}
This pattern moves the responsibility of managing the value
prop from the input to its parent.
This is called a controlled component because the parent is in control of setting the value
prop,
in fact, the input couldn't change its value even if it wanted to, it will always render the value
prop it is given.
Using controlled components is great for flexibility, and helps keep the data flow going in one direction, but it can become tedious to wire up the components every time, even if you don't need the benefits of controlling it. To mitigate this concern React introduces the concept of an uncontrolled Component.
function MyInput() { return <input type="text" defaultValue="hello" />;}
This input doesn't provide a value
prop, instead it uses the defaultValue
prop to set an initial
value for the input. After that initial setting, the input takes over and manages the value itself requiring
no more input from the parent. This is much simpler to set up, but is not conducive to setting the input value
from outside the input.
Controlling anything
We can extend this pattern to more than just value
props, lots of things can be controlled or uncontrolled.
In React Formal for instance the Form
component lets you control the errors
prop for setting
the current errors in the form.
// controlled<Form errors={this.state.errors} onError={errors => this.setState({ errors })}> {/* fields omitted */}</Form>// Uncontrolled<Form> {/* fields omitted */}</Form>// and Uncontrolled with an initial setting<Form defaultErrors={this.state.errors}> {/* fields omitted */}</Form>
So when a prop is said to be "controllable" it means that you have the option to let the component handle it, or if you need finer grained control over how that prop updates you can jump in and handle it yourself.