The concept of controlled and uncontrolled components in React
is in relation to forms. In React
, form elements typically hold their own internal state, so their functionality differs from other HTML
elements. The different ways to obtain the internal state of form elements give rise to controlled and uncontrolled components.
In HTML
form elements, they usually maintain their own state
and update the UI
as the user inputs. This behavior is not controlled by our program. However, by establishing a dependency between the state
property in React
and the value of form elements, and then updating the state
property through the onChange
event paired with setState()
, we can control the operations that occur in the form during user input. In React
, form input elements controlled in this way are called controlled components.
When defining an input
box in React
, it does not have the bidirectional binding feature seen in Vue
with v-model
. This means that there is no directive that can combine data with the input box and synchronize the data as the user inputs content into the input box.
When a user inputs content into the input box on the interface, it maintains its own state
. This state
is not the same as the usual this.state
we see. Instead, it is an abstract state
on each form element. This enables it to update the UI
according to user input. If we want to control the content of the input box, and the content of the input box depends on the value
property in the input
, we can define a property named username
in this.state
and specify the value
on the input as this property.
However, you will notice that the input
content is read-only at this point because the value
is controlled by this.state.username
. When the user inputs new content, this.state.username
does not automatically update. As a result, the content inside the input does not change. At this point, the console usually throws a warning.
This warning actually provides the solution to this problem. We just need to listen to the input content changes with the onChange
event of the component and update this.state.username
using setState
. This way, in the current component, we can control the value of this form element, which is a controlled component.
It's also important to note that although this component is a controlled component, there are drawbacks if it is used as a shared component for invocation. Even though the Input
component itself is a controlled component, the calling side loses the control to change the value of the Input
component. Therefore, for the calling side, the Input
component becomes an uncontrolled component. Using an uncontrolled component's usage pattern to call a controlled component is an anti-pattern. Examples below will be written in Hooks
.
If the component provider or the caller need the Input
component to be a controlled component, the provider just needs to give up control.
If a form element does not go through state
but is modified through ref
or directly manipulating the DOM
, then its data cannot be controlled through state
, and this is what we call an uncontrolled component.
state
.value
or checked prop
.state
of a react
controlled component:
state
.onChange
event handler is called.event
and updates the application's state
.SetState
triggers the view to re-render, completing the update of the form component value.value prop
, it can be termed as an uncontrolled component.state
or props
.ref prop
needs to be added to access the rendered underlying DOM
element.value
by adding defaultValue
.