Back
React: Controlled vs Uncontrolled Components
Let's talk about controlled vs uncontrolled React components, with some examples. We’ll discuss their advantages and disadvantages, and finally, we’ll look at the Formik library.
Let's talk about React controlled vs uncontrolled components. We’ll discuss their advantages and disadvantages, investigate some examples along the way, and finally, look at Formik, a form library available in the React ecosystem.
Without further ado, let’s get started!
Prerequisites
To follow along with this article, I would highly recommend reading these articles for some background:
What is a Controlled Component?
Controlled components are components whose value is directed/driven by React’s state. By state, we mean the state we store inside a React component, i.e., inside this.state
or with useState
.
This means that these components will receive the latest changes.
For any controlled component, we pass our state variable inside the value
prop of the component. The function that changes this state
variable of the component is passed in the onChange
prop of the controlled component.
Here is an example that demonstrates a controlled component:
Let’s explain:
App
is a simple function-based React component.Its
render
method consists of aform
with aninput
element and astrong
element that displays the value of the state variable of the component.We pass the state variable
inputValue
as avalue
prop to the input element.Similarly, we pass the
handleOnChange
function to theonChange
prop of the input component.Now, whatever you type inside the input element will set the value of the
inputValue
state viahandleOnChange
, and then the same will be displayed in theinput
element.To show that the state variable
inputValue
is changing, we display it inside thestrong
element.
The controlled component’s value
prop does not always need to be a component’s internal state. It can be a prop of the parent component, or it can come from the Redux store. This is similar to the onChange
prop.
In a similar manner, we can use react-redux
to get the state and the handleOnChange
function from the Redux store to have similar functionality to what we had when we were using useState
.
The same context can be applied to the checkbox, radio, text area, and select DOM elements so that they can act as controlled elements.
Here are some of the advantages of using controlled components:
The UI and the data are in sync
Form data can be passed between different components
The event handler and the value prop can be from the parent or a redux store
The React component acts as a source of truth for this component
Some disadvantages of controlled components:
They render at each input change
A controlled component can be a bad choice when large changes are required to be made to the component
What is a React Uncontrolled Component?
As the name suggests, the value of uncontrolled components is not driven by the React component’s state variable. It's completely controlled by the DOM.
Uncontrolled components are generally used when the use case is simple or the action is not trackable; for example, a user uploading a file using file input.
The basic requirement of any uncontrolled component is to be handled by the DOM. In this case, we cannot pass the state
variable inside the form’s input element. Now the question arises — how are we going to set the value inside this input element?
We use React’s useRef
for functional components or createRef
for class-based components. A useRef
is a hook that returns a mutable object with current
as its property with value being initialValue
that is passed inside the hook.
Here is the syntax of the useRef
hook:
A ref
object can be used in many ways, e.g., as a state variable that does not re-render the component on change, to access DOM elements, etc.
We can leverage this into our React uncontrolled component to access input elements attributes, i.e., value properties.
Here's a simple example of how you can create an uncontrolled component:
As you can see, this App
component consists of form
and a bunch of span
elements. We use the JSON placeholder API in the component to fetch the post based on id
. This is the summary of our component, but let’s understand a bit more about how the App
component works internally.
Inside the
form
element, we have a staticselect
element with a couple of options.We are making use of a
ref
object here. Thisref
object is named asselectRef
and this is being passed on to theselect
element as aref
prop.Here comes the catch— we don’t need to watch for any changes that happen to the
select
element, nor do we need to make use of a state variable to keep track of the current value that is selected in this element.This begs the question, how do we get the latest value from the
select
element?Well, we don’t need to. This is an uncontrolled component/element; a component/element that is managed by the DOM.
So, the change in the
value
property of the select element is managed by the browser.Now we just need to find a way to capture this value.
refs
comes to rescue here. Since we passed ourref
object into theselect
element as a prop, we can now access the value present inside this element.To get hang of this, you can check out the
handleOnSubmit
function. This function makes use of theselectRef.current.value
to access the value property of theselect
element. TheselectRef
stores all of the values inside thecurrent
object. In this case,selectRef.current
will store theselect
element itself. To access the value, simply access its.value
property.Next, the
handleOnSubmit
function calls the API. On success, we simply store it in the state variableapiData
.
Here are some advantages of uncontrolled components:
No component re-renders
Browser DOM handles the changes to the element
Simple to use
Keeps track of the internal state
And some of the disadvantages of uncontrolled components:
Cannot be used in complicated scenarios where we need to pass the value to different components
It’s not always efficient to use uncontrolled components where we require granular control over the value
Formik
Formik is an open-source library to build forms in React and React Native. It’s the world’s leading library for building forms in React.
Formik is a complete solution that helps you to implement form validation, keep track of visited fields, and handle form submission in an efficiently and robustly. It's based on the concept of a controlled component react.
Now, let’s look at one simple example of how can Formik can be used to build a form along with the form validation.
We are going to use the same uncontrolled component example. First, we’ll convert the example into a controlled component and then, use Formik to make our life easier.
Here are some of the brief points that will get you up to speed on understanding the above component:
The Formik library provides us with some easy-to-use components that help us to build Formik forms in no time.
Formik is a wrapper component that helps to build forms.
It takes in
initialValues
, which tells the Formik form about the fields and their initial values.Next, we have the
validationSchema
prop. It can accept a Yup object to define validations inside the form.Finally, we provide our
submitHandler
function as a callback that needs to be executed whenever a submission takes place.This is a controlled component. All the values are handled by Formik.
In the above component, we have used
Formik
,Field
andErrorMessage
components. These are similar to the normal input elements present inside the form element.The
Field
component, as the name suggests, acts as a wrapper component on top of form input elements.Finally, we have the
ErrorMessage
component. This component takes in thename
prop. Thisname
prop will be used by this component to provide an element that displays the error message for that particular field.Now, you might be wondering how these components know which field they should work for. Here comes the
name
andid
props to the rescue. You should provide either of these props to make sure yourField
andErrorMessage
components work properly.We should also make sure that we pass the submitted values to Yup’s
validations
that we set earlier. For example, for the select field, we pass inname="selectVal"
in theField
andErrorMessage
components. In this way, Formik knows how to map these wrapper components to their respective fields.
Summary
Now, you've learned some of the differences of React controlled vs uncontrolled components. Choosing which type of component to use in your project completely depends upon your use case.
If you’re looking for tangible results with a simple use case or trying to use memory-intensive operations, such as document editors, uncontrolled components are the way to go.
If you’re looking for more granular control over the values of form elements, then you should use controlled components.
Become More Productive Writing Your React Apps
Every component you create in React requires tons of repetition. Across every frontend project, there are custom setups and best practices that teams follow. Pieces helps you with any React project by creating a local micro-repository where you can store any code snippets and their relevant metadata on your machine. Additionally, Pieces makes it incredibly easy to share your snippets, create collections to onboard others onto a project, and even integrate your snippets directly in your IDE. Our team of developers is pushing changes every day to build the most effective and efficient micro-repo for you.
Try Pieces now using the personal plan for free and supercharge your React projects!