This course has been updated! We now recommend you take the React Performance course.
Transcript from the "Managing State in a Form" Lesson
>> So, let's talk a little bit about managing state in forms. And so, we've got this form right here, it doesn't have that many fields. It has a username, an email address, a password, a confirm password. And do you wanna help us out with an angel investment, because this is a startup that doesn't actually have a product yet.
[00:00:15] And they're just trying to collect your data, so they can hopefully sell it. But you might wanna sign up so you can squat on your username, just in case it is the next big thing. And what I wanna point out is one of the tricky parts of this whole hook thing, which is, there are not that many fields on this form, right?
[00:00:35] We could have taken it to its natural conclusion, right? And we could have had first name, middle initial, last name, address one, address two, state, ZIP. The four numbers after the ZIP code that nobody actually knows, even though they could definitely calculate that with the address. I don't even know why I need to put in a city and a state when I give them a ZIP, it doesn't matter.
[00:00:57] And we can see that even this is getting slightly tedious. Clearing it is involved with doing all of this as we go along. We need a custom onChange event for every single one. And this is an area where I would argue that hooks are a little bit more cumbersome than setState.
[00:01:18] Cuz setState, you can give it an object with all of the different parameters and you wouldn't have to worry about it. You just give an object with the keys and the values. And you set multiple things at once. Handles are changing. You could have a handle change, which could look something like this.
[00:01:33] This won't work yet. Because each one of these input fields has a name that maps to the state key and has a value. So, if you were using this.setState, you could have done something like this. You could have said this.setState and the key on the object is whatever the, The event.target.name is.
[00:02:01] And the value, it's gotta be an object, we'll fix that in a second, event.target.value, and you can put that in a little object in here. And you could have given this handleChange to every single one of those form fields. Because they know it triggers on the input field.
[00:02:20] So, it would have been name, username, value is whatever they changed it to. Instead, we need these custom functions every time. Clearing it is calling each one and reset it. Could we do something with useReducer? Totally, and in a way, we will. But what would be cool is could we implement something suspiciously close to this.setState using the primitives that we have in hooks?
[00:02:49] And spoiler alert, I didn't do all that set up and make us switch to this repo to have the answer be no. That would have been rude. And I'm not rude. I'm many things, but not rude. And so, what we'll do is we'll make a brand new one.
[00:03:02] And this is how you can simulate some of the behavior. Obviously, we're not gonna get to the point where it takes functions and all that kind of stuff. We'll do the basic part of an object, we can replace multiple values. And so, we'll call it useSetState. Cuz that's not gonna be confusing.
[00:03:18] And here we'll import useReducer. From React. And our reducer is simply going to take the previous state of the world, and this object that represents all the new state, and merge them together. Just like we talked about earlier in this course, right? this.setState takes all the objects and merges them all together.
[00:03:41] That is exactly what we're going to do. Except we're gonna take two objects, we're gonna take the previous state of the world, and all the new things that they set. And we'll just merge them, exactly the way that a very overly naive way of this.setState would work. So, we'll say reducer, and we'll say the previousState.
[00:03:59] And this would be what we would normally call state, is an object. And what would normally be an action we'll just call it updatedState. Right, so all the things that they're changing. We'll make that an arrow function. And what we'll do is simply return, All of the previous state.
[00:04:21] And this is why I showed you that slide in the very beginning, right, that if you show something, you should have to do it later. Just merge those two objects together. Previous state of the world, the new state of the world, merge them together, that will combine them the same way this.setState does.
[00:04:37] And then let's make this useSetState hook. We'll say const useSetState. Give the initial state, it's just some object, if they didn't give us one. And that'll be an arrow function. And then we just say the state and the dispatch is going to be useReducer. With the reducer we just wrote up there.
[00:05:09] And the initial state that they're passing in, which will either be what they passed in, or an empty object. That's how we defined it. And we'll make this setState method, which is going to be take their updated state, because we have the previous state of the world. This is simply a function, it's going to take the updated state.
[00:05:27] And it's gonna dispatch. So, now we return the current state of the world and this method that will combine a new object and merge them together. We'll say export default useSetState. All right, so now we have this abstraction that gives us something very close to a very naive.
[00:05:55] As an exercise to the reader, you could take this to its natural conclusion and implement, okay, well, if it's a function do this, right? You absolutely could, if you wanted to go that far. But I would argue, what is it actually serving you at that point? And we can use this quick abstraction to clean up a little bit.
[00:06:12] And there's also an argument that you can use a useFormState here, where you could take that new state of the world and run a bunch of validations on it, right? Okay, does the password field have an emoji in it, right? So on and so forth. You can begin to take complicated things and use these patterns to solve for them.
[00:06:29] And so, all right, with userSignup now, we can begin to slim this down a little bit. So we might have an initial state, which I could do inline, but I'm just gonna call it out here. The initialState of this form, which we'll need for setting up our state to begin with.
[00:06:43] And also when they hit reset, we want to put it back to its initial state. That's the only reason I'm making it a variable in this case. And that is gonna be what? userName is empty string, and email is an empty string. And, whoops, Password, empty string. We'll just do those for now.
[00:07:11] We're gonna leave the checkbox checked, if they wanna angel invest with us, it'll be great. So, we've got that initial state. And now what we can do is we can begin to do effectively what I was hinting at before. And so we've got this initial state of the world.
[00:07:27] So now we could do something like this. We could do, useSetState with this initial state. Clear can go ahead and do something like this, where it's going to be setState back to the, nope. So, it's gotta be state and setState. So now clear is simply set the state back to the initialState.
[00:08:05] Right? And then we can make that handle change that I was telling you about before. So, handleChange, I should have just left it there since I can use it now, but here we are. Will be setState. And it's going to be, event.target.name, event.target.value. And so we got rid of all of those one by one state hooks in there, right?
[00:08:40] All we need to do next is just for these values, and we can cheat a little bit here, I'm gonna grab all of them. We'll have the state.username, and then the onChange for each one of these is going to be the same handle change event, right? And this is what we would have done with the setState, but it was harder with all those individual hooks.
[00:09:05] Could you also write a reducer that knew about all the details of this form? You absolutely could. I'm just saying that anything you can do with setState you could theoretically implement yourself as well with the hooks. So we need to change these all to the same handle change function.
[00:09:24] That'll be state.investmentInterest, this one is gonna be a little bit different cuz check boxes, we're not actually setting the value there, but. We'll do, what was it, investmentInterest. So, we'll have state.investmentInterest In this case we'll just say setState, it's the opposite That one's a little bit different than the generic handle change, but all right.
[00:10:05] So now what we're able to do is clear away all of those individual sets. We can use basically the same function for every text field, password field, email field, so on and so forth, right? Again, that reducer pattern helps with a lot of things that you find yourself.
[00:10:19] What I would love for you to do is train this little piece of you that if you find yourself going like, this is getting tedious with useState, pulling out some kind of reducer is probably the the way forward. useSetState. Let's see what the issue is. It's in this file over here.
[00:10:37] React is lowercase.
>> You'll notice that it was not the first time I made that issue. [LAUGH] So, now we can change everything in the field. Everything works the same way with just a simpler abstraction.