Keep UI and State Synchronized Using Controlled Components in React with Redux

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

You must be a Member to view code

00:00 Currently, our application is dispatching an action using a set time out. This isn't a realistic use of the store's dispatch function, so let's remove this and use dispatch for something useful. I'm just going to delete the set time out and everything else in here can stay. Our browser will reload and we'll just have our three initial todos.

00:18 Now, I'm going to open up the todo form JS file. Let's refactor this a little bit. I'm going to come down here and I want to make this a block, which means I'm also going to need a return statement for my JSX, so I'm going to move that into the function body and just add a return.

00:35 Now, at the top of this function I want to destructure my props. I don't have any props beings passed in at the moment, but we're going to need to pass in the value for the input because we're going to get that from the store.

00:46 Let's destructure props into, for right now, just currenttodo and that will be the property value that we grab from props. Of course, we need the equal sign there. I can save that. Everything should keep working as expected, we're not doing anything with this currenttodo yet.

01:04 I'm going to come down here to my input and I'm going to sign this as the value, I'm going to make that currenttodo. In order for this currenttodo to have any effect on our UI, we're going to need to get a value into this input.

01:17 I'm going to open up todo.js in the reducer's directory. This is where we are defining our initial state, and I'm going to add a currenttodo property to that. For now, I'm just going to put a temporary value in there, we'll just call it temp and I'm going to save that.

01:35 Now, I want to go to index.js where I'm getting my state and I'm passing it into app. Instead of spreading out the entire state I want to break this up into the pieces that we have so far. I'm going to have todos and I'm going to set that to equalstate.todos, and then I'm going to do currenttodo and that's going to equal state.currenttodo. I'll break this onto multiple lines so it's a little easier to follow. I can save that.

02:10 Now, that I'm passing that down we're going to add.js and I want to pass currenttodo into todo form, and in add.js that's going to be referenced through this.props.currenttodo. We can save that. When the app reloads this time, we're going to have a value in the input.

02:31 If we open up the developed tools and look at the console we're going to see that we have a warning, because we have provided to a form field without an onchange handler. We need to go back into todo form and give this an onchange handler so that we can control the value of this input.

02:48 I'm going to drop value onto the new line and we'll give a separate line for onchange just to make this easier to read. Onchange is going to be referenced to a function, so I'm going to handle input change.

03:03 Then let's define this. I'm going to define it right up here. This will be consthandleinputchange, and that's going to be a function that's going to take an event object, and then we can grab the value for our input off of that when object. I'll define constval and we're going to set that to equalevent.target.value.

03:25 Now, we need to do something with this to get it back into our store. Let's save this and we'll see that our warning's gone away but now we have a new warning that val isn't being used. Let's go to find a function that we can use to dispatch an action so that we can get this value into our store.

03:40 I'm going to go up to index.js and I'm going to define a new function. We'll this const, call it todochange handler, and this is going to be a function that's going to take in a value, which we'll call val, and this is going to call store.dispatch. It's going to use that value to dispatch an action.

04:05 Our action objects all have a type. We'll give this type a value which we'll call current_update. Then we're also going to give it a payload key and payload is going to be our value.

04:23 Now that we have that defined, let's take this function and pass it down into our form component. I'm going to pass this down as part of app and I'm going to call this change current. Then I'm going to just going to set that to equal, a reference to that todochange handler function that we just created.

04:45 With that done we can jump over to add.js and in my todo form component I'm going to break this down into multiple lines and I want to pass that function through. We can call it changecurrent again. That's going to be equal to this.props.changecurrent. We can save that.

05:08 Then back in todoform.js, I can use that function that I'm passing down by grabbing it off of my props as changecurrent, and then I can call it here with that value that I'm grabbing off of the input. I'm going to save that.

05:25 Then when I reload all the warnings are gone but we're still not quite there because our reducer isn't handling the action that we're dispatching with this changecurrent function. If we go on we look at index.js really quick, we'll see that the action that we're dispatching is current update and the payload that we're dispatching is the entire value of the input.

05:46 Knowing that we can go into todo.js, we can add a case to our switch for current update. Anytime that action is dispatched we're going to return a new copy of our state, so we'll just take the existing state that's been passed in, we'll spread that.

06:05 Then we want to replace currenttodo with the payload from our action. We'll just, action.payload, and then we can save this. Now if I go into my input I'm able to type characters in. If I look at this in the reactive tools we'll see that as I change the input it's going to change the currenttodo prop in my app component.

06:33 That's getting passed all the way down to the todo form component. With that done, I can go up here and we can remove that temp value and we'll start with an empty input like one would expect.