When you learn deeper about React, you will eventually hear about controlled and uncontrolled components.
In this post we will learn about:
- The difference between controlled and uncontrolled components.
- When to prefer one over the other and why it matters.
The “only” difference
It all comes down to one thing: how the component does state management.
Although that’s the only difference, it has a big impact on how we use the component.
Let’s take a look on how native <input>
s are used in a controlled vs uncontrolled way.
Controlled input
You know you’re using a controlled component when you:
useState
to store the component value every time it changes.- Pass the value back to the component to display the updated value.
This is how you use the input in a controlled way, which has several implications explained below.
Where the state is managed
MyForm
is responsible for managing the state of the input.
The name
state defines the displayed content of the input.
Every time the input value is changed, MyForm needs to call setName
to keep name
up to date.
Reading the input value
When you want to validate or submit the form data, you can use the name
state to get its current value.
Changing input value
You can set the name to any value at any time you want
Performance
Everytime you set the name, re-renders will happen.
As an example, I’ll add a console log to get notified when re-renders happen.
This is what we’ll see in the console if I type “Samuel” in the input box
When using controlled components in a complex React component, be mindful about re-renders.
Try it yourself using this sandbox below.
Uncontrolled input
Now let’s take a look at how uncontrolled input works.
defaultValue
is set instead of value
.
value
must not be set otherwise the component will count as a controlled input.
Where the state is managed
The parent component doesn’t need to do anything.
No need to use state to store its value and pass it back to the input.
The uncontrolled component is responsible for managing its own state.
Reading the input value
There are two ways to read the input value
Use ref to get the reference to the input component
Use ref to store the input value
Note: While it is possible to store the value in useState
, it will trigger a lot of re-renders. This is the same drawback we get from using controlled components.
Changing the input value
We only have one chance to set the text displayed by the input, when the component is mounted through the defaultValue
prop.
There is no way to set the input value after the component is mounted.
Note: It is possible to “cheat” this by using refs to change the input value, but in general it’s impossible for most custom React components.
Performance
If we do console logs like previously, no re-renders will happen at the parent component.
Uncontrolled components tend to have better performance by default.
Now try the sample below and compare it with the controlled inputs.
Open source samples
MUI supports both controlled and uncontrolled mode for its input components: Rating, Autocomplete, Select, Slider and many more.
Although I haven’t checked in other UI libraries, I’m pretty sure a lot of them will have both controlled and uncontrolled modes.
Controlled vs uncontrolled: which one to use?
This is how I decide whether to use controlled vs uncontrolled inputs.
Do I need to change the component’s value from the parent component after mount?
I’ll use controlled component if the answer is yes, otherwise uncontrolled component would be my default choice because of performance reason.
What’s next?
In the next next post, you can learn how to build a custom component that supports controlled and uncontrolled mode.