Controlled and uncontrolled components

Controlled and uncontrolled components

At this point in the course, I must make an apology. I haven’t been telling you the whole truth, because:

React often renders information that isn’t specified by elements and props.

Now obviously, this isn’t always the case — after all, most of what you’ve rendered so far has been completely controlled by its elements and props. In fact, React goes to surprising lengths to make sure that this is so…

#Controlled components

Imagine that you’re building a form — perhaps to add people to your contacts app. As with any other web app, your form is going to have an <input> element. The difference is that with React, you can configure your <input> declaratively, using props.

Say that you already know the name of the person the user will be adding, so you want to autofill the input. React makes this easy! By setting a value prop on the <input>, React will render it as a controlled component — a component whose appearance and behavior is completely defined by its props. This way, the input’s value will always match its props. The user won’t be able to interact with your control at all.

Wait, what?!

index.js
import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(
  <input
    type='text'
    value='Jamse'
  />,
  document.getElementById('root')
)
Build In Progress

The thing about React <input> elements is that they’re kinda boring. They take a value prop, and then display it. What they won’t do is change the value prop, because components can’t directly change their own props. Props are a one way binding; they only allow data to flow from parent to child.

But if props only allow data to flow in one direction, then how can you set up a working <input>? Actually, there are two ways.

First and foremost, there are event handlers. These are my recommended approach, and along with React hooks they give you a simple but powerful way to build complex forms and flows. We’ll cover all this in detail in the next section.

But there’s also another way to make interactive controls: you can give them a mind of their own.

#Uncontrolled components

Imagine that you’re building a form — just like the one in the above example. But this time, you forget to give it a value prop at all.

index.js
import React from 'react'
import ReactDOM from 'react-dom'

const App = (props) =>
  <div>
    <input type="text" />
    <span> rendered {props.count} times </span>
  </div>

let renderCount = 0
function render() {
  ReactDOM.render(
    <App count={renderCount++} />,
    document.getElementById('root')
  )
}

// Render the App component once every second.
window.setInterval(render, 1000)
Build In Progress

Go ahead, try typing something in the input. When you do, you’ll notice that even after re-rendering, the input will keep its value.

This is what we call an uncontrolled component; it can take on different states, even while represented by the same element. And this raises the question — how does this actually work? Where is the state stored? Have a think about it, and then when you’re ready check your answer below.

Without providing a value prop, React just lets whatever you type stay there! In contrast, for controlled inputs, React actually resets the DOM node’s value attribute after each keystroke.


While the terms controlled and uncontrolled components are most often applied to form controls, they illustrate an important dichotomy that you’ll see over and over again in the React world:

Some components have internal state, and some don’t.

Components with internal state tend to be quicker and easier to add to your app, but they’re harder to reason about down the track. This tradeoff is the subject of endless discussion amongst React developers. Indeed, we’ll discuss it in a number of lessons later in the course.

But before using uncontrolled components at all, there’s something you need to know.

Progress to next section.