Synchronize React UI and State with Controlled Components

Andy Van Slaars
InstructorAndy Van Slaars
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 6 years ago

We’ll make the input field a “controlled component” by reacting to each change of the input and capturing it in the component state. Following this model gives us assurance that the UI is always a representation of the current application state.

[00:00] In React, our rendered view should be a function of the application state. This means the changes to our state should be reflected in the view. As we see with the checkbox being checked, for toDo where true is a complete flag. This also means the changes that come from user input should be reflected in our state.

[00:17] If I type something into this text box, we'll see that displayed in the view, but it isn't tracked in our state anywhere. We always want our state to be in sync with our view. Let's go ahead and fix this.

[00:29] Let's start by adding another property to our application state. I'll add a "," after our toDos and I am going to create a value called "CurrenttoDo." For now, I am going to set that to an empty string. I'm going to scroll down to my forum and in my input, I'm going to set the value to =this.state.CurrenttoDo. After it refreshes we'll see that our input is empty.

[01:00] Now, when I try to type into here, nothing is going to happen. That's because my value is set to that empty string, and currently, I have no way of changing that. In order to allow input, we need to create an event handler that can capture the input and assign the value to the current ToDo property in the component state.

[01:16] Let's start by adding a method to the component. I'm going to call that HandleInputChange. That's going to accept an event. It will get the value of the text input by calling event.target.value. We want to use this to reassign the current toDo property in our state.

[01:40] If you're new to React, you're first instinct might be to call this .state, .CurrenttoDo and reassign it using this incoming value. Instead, what we want to do is call the components, setState method and pass in a new value.

[01:53] First, I'll get rid of this reference to the current toDo, and I'll call this .setState. I'm going to pass .setState an object. This object is going to contain the key or the keys that I want to update, along with their new values.

[02:09] I want to update the CurrenttoDo value and I want that to be this event.target.value, so paste that in there. In order for this method to update our state, we have to do two things. First, we need to reference it in our constructor and bind it to this.

[02:25] I'm going to move up into my constructor code. I'm going to call this handle.inputChange and I'm going to set it =this.handle.inputChange again. This time calling bind and passing in this for our this context. This is to ensure that when we call this.setState inside our method, this refers to the correct context.

[02:45] The second thing we need to do in order for this handle input change method to update our state is to set it as the handler for the onChange event over input. I'm going to drop down to where I have to find the input field. I'm going to add an attribute for the onChange event and I'm going to assign this.handle inputChange.

[03:06] I save my changes, the browser's refresh. I'm going to open up my DevTools. I'm going to the React DevTools. We'll see that CurrenttoDo is part of my state. I'm going to come up to my input. I'm going to start typing a value in.

[03:25] As I type each character, we're going to see the CurrenttoDo in our state down in DevTools gets updated to reflect the current value of our input.

[03:35] By doing this, we've ensured that our view as a function of state, keeping the rendered output and the state data in sync.

Janusz
Janusz
~ 7 years ago

@Andrew, why don't you use ES6's arrow function for handleInputChange, like:

handleInputChange = e => { this.setState({ currentTodo: e.target.value}) }

  • no binding needed. Is there any drawback of doing it this way?
BlockOperator
BlockOperator
~ 7 years ago
MilesWells
MilesWells
~ 7 years ago

@Andrew, why don't you use ES6's arrow function for handleInputChange, like:

handleInputChange = e => { this.setState({ currentTodo: e.target.value}) }

  • no binding needed. Is there any drawback of doing it this way?

The reason this works is because an arrow function's 'this' is automatically assigned to the context in which it is defined. You cannot rebind an arrow function's 'this' using .bind, .call, or .apply. You also need to pay attention to hoisting if you use arrow functions.

I like using ES6's class members and arrow functions because it's more concise, but I would like to know if I missed any drawbacks of using them.

Markdown supported.
Become a member to join the discussionEnroll Today