 FrontendArmory
FrontendArmoryIn an earlier lesson, we looked at uncontrolled inputs. To jog your memory, these are inputs that can have different states for the same set of props. For example, an input element without a value prop will look different after you’ve typed in it, so it is uncontrolled.
In fact, it’s not just inputs that can be uncontrolled. Class components that store state can be uncontrolled too. And this raises the question:
Are stateful class components… the dark side?
Let’s consider the App component from your contact list app. It fetches an array of your billionaire friends in componentDidMount()… and stores the array under this.state.
But the thing about your App component is that the state never leaves it. Unlike uncontrolled inputs, your App component doesn’t have any callbacks. The state is contained.
You can’t escape the fact that one way or another, a useful app is going to have state. The trick is, you never want that state to escape its container component.
Container components, or containers, are a name that people use for components that primarly manage state. Containers don’t usually render any DOM elements, instead passing their state to child components that handle presentation.
As you’ve probably guessed, your App component is a container component.
In contrast, presentational components are those that handle markup and styling. They don’t usually have any state. They can be class components or function components. And they can have callbacks — but the handlers just forward events to parent components via callback props.
Your contact app has a number of presentational components. In fact, the very first components that you build — Contact and ContactList — are presentational components.
But what about your ContactForm component?
Let’s take another look at your ContactForm component.
When the user clicks the “Add” button, a contact details object is passed out as an argument to onAddContact(). For example, if you were to add a mythical Japanese character to your contacts, the call to onAddContact() may look something like this:
this.props.onAddContact({
  name: "Momo Taro",
  email: "momotaro@example.com",
})The problem with this is that the state is now in two places:
onAddContact function just left itNow you may be thinking, but you could just clear the form — then it would only be in one place again? And sure, this might work. But then again, it might not. Can you think of some reasons why?
The form component itself has no control over what the onAddContact function does.
If you clear the form whenever “Add” is pressed, the user could lose their data!
The problem with uncontrolled components is that they cause state to be in multiple places.
Luckily, you rarely ever actually need an uncontrolled component. And if you do end up with one by accident (or because I didn’t explain things properly the first time), then there’s a simple process to fix it.
Whenever you find yourself with an uncontrolled component, you can convert it to a controlled component by moving, or lifting, the state into a parent component.
To lift state out of a component, you’ll need to do three things:
this.props instead of this.state.onChange prop, instead of calling this.setState().Let’s practice this by rewriting your contact form.
To start you off, I’ve updated the propTypes object to your ContactForm component, detailing what the new props should look like. I’ve also added a newContact object to your App component’s state.
Your task is to:
this.state from your ContactForm component.ContactForm component.App component.A few hints:
onSubmit handler doesn’t need any arguments. The form component just needs to notify its parent that “submit” was clicked.this.props.value, and pass that as an argument to this.props.onChange.You’ll know when you’re done, as everything will work as expected, and ContactForm will no longer have any references to this.state!
If you do get stuck, take a peek at my solution. And then go back and finish off your version.
And once you’re done? Then click on through to put the final touches on your contact list. And after that, we’ll discuss what comes after this course.