- Read Tutorial
- Watch Guide Video
Now, I will warn you that if you've ever worked with HTML forms in some other language or framework, what we're gonna walk through may seem a little bit convoluted. You have to take a few extra steps that usually you would not have to take.
But the more times you go through it, it does start to feel more natural, and hopefully, you'll even enjoy the experience because it really separates each stage of the data flow.
So, in a normal type of situation, so if you're building out a form in, say, Rails or PHP, you'd build out a single form and then when the form is submitted, the data gets passed up, and that is really the only step between the client and the server.
In React, what we do is we build out the form. The form, as the user is typing in, that updates the state, so, you have this step where you're capturing the data in the state. Then when the user hits submit, then you build a handler for being able to manage what you want to occur after that form has been submitted, and so you can go and grab the state values and then pass them up.
So, there are a few other kinda steps that you need to take, and we'll walk through each one of them. The thing that I like about this process is it really compartmentalizes each stage of the development process. I know that I need to update the state, I know I need to build the form, I know I need to build a handler for managing the data so it ends up taking a little longer, but I do like being able to separate and segment each one of those steps.
So, let's start building that out. I'm gonna start by going into the login component and adding a constructor. So, I'm gonna say constructor, and we will take props eventually so I'm just gonna add those in now and I'll say super with props, and then from there, let's define our state.
So, I'll say this.state and the object for state is gonna start off with an email, it'll start as an empty string and then a password that'll also start as an empty string, and so, those are gonna be our two items there. We will add a method as we will do shortly, but for right now, this is all that we need to do.
Now, coming down to the JSX in the form, there are a couple of things we need to do. First, we need to add an event handler for what happens when the form is submitted. So, for form, that event handler is called onSubmit, and then what we wanna do here is just pass in a function.
So, this is gonna be the function that handles that submission process. So, I'm gonna say this.handleSubmit, just like that, do not add the parens after it or else if you do, it'll get run as soon as the form loads, which is not what we want, and we'll add our CSS classes later, so don't worry about that right now. And now let's go and let's work on these inputs because, with these inputs, we do have quite a bit to add.
We're gonna start with the type and we're actually gonna change this to be of type email, and then I'm gonna put each one of these on new lines. The next thing that we need is we need a name attribute. So, with this name, I'm going to say email.
Now, I don't want you to get confused with the type and the name. The type is something specific to HTML, so, if this right here wasn't called email but it was called username, we would not change the email, this is something specific to HTML, this name is something that we can change to whatever we want.
So, I'm gonna say email because what we have here in the name is going to map directly to what we have in state. So, if you do, use something different like a username. Make sure that you have it matched up in those spots and you'll see why here in a second.
So, after name, let's add a placeholder and this placeholder, we can just say something like your email, something like that. And then we need to provide value and this value is going to be the value of the state. So, its gonna be this.state.email, so it's gonna start as an empty string, and then lastly, we need our event handler, this is gonna be onChange
.
So, every time this form changes, this is going to be triggered. And so, here I want to call, in curly brackets, this.handleChange, which is gonna be a function that we create. So, so far, we're calling two functions that we haven't created or defined yet. So, don't worry about that, we're gonna do that in a second.
I'm just gonna copy what we have here for the input and place it down here for the password. And so, the type here is password, the name is password, and the placeholder is Your password, your value is going to be password, and then the onChange does not change at all. Lastly, we need a Submit button.
So, right here, we can wrap it in a div that we will style later, and then just give us a little bit of room, and then I just need a regular button, and we'll say Login, and then let's also add this, this is of type equals submit so that the form knows whenever we press down on this button, it will automatically submit the form.
Now, if you save this, it's just going, let's look over here. If you come back, then nothing is gonna happen because we haven't actually defined any of our actions yet, so let's start doing that now. We have two functions, we have this handleChange
and handleSubmit
. For both of these, let's just console.log what would happen when they're called.
So, for handleSubmit, this is going to, by default, take an event, and so, let's just console.log that out. So, Handle submit comma event and if you're curious about how it got event when we weren't passing anything in, remember that our event listeners are automatically passed in an argument when we call 'em like this.
So, you could imagine this saying something like this.handleSubmit, and then it's getting that formsubmitevent automatically, but we do not put that in there, it's just passed in because we're passing this to an event handler. So, that's our handleSubmit.
handleSubmit(event) {
console.log("Handle submit", event);
}
Now, this other one is handleChange. So, say handleChange and for this one right here, we're also going to take the event and then let's also just console.log this handle change and paste in the event, and then lastly, remember we have to bind this to the component.
So, say this.handleChange equals this.handleChange.bind.this and then we just duplicate this for the handleSubmit, and that should be all we need to do.
login.js
this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { console.log("Handle change", event); } handleSubmit(event) { console.log("Handle submit", event); }
Let's test this out and see if it's working up to this stage. Make sure you open up your JavaScript console and let's move it to the bottom.
Okay, so now that we have that, you can clear the console just so we have some room. And if you come here and just start typing anything, so, you could say asdf@asdf.com, you may notice something kind of weird, right? It's not populating the form and you may think that we have a bug, but actually we just haven't finished out the implementation and it's working perfectly.
So, what's happening here, every time that we are typing something in, it is handling the change. You can see if you scroll up. You can see all of the changes that it picked up. So, in a sense, it is working, but what is the problem?
Well, the problem is actually, if you come back to the code and come down to the form, we are setting the value of this.state.email. So, this value is overriding everything, which means that because we're not updating the value, it is always remaining just an empty string.
What our handleChange event needs to do is actually take the value as the user is typing and update the state during that process, so let's do that right now. So, we know that it's working, it's handling that change, it's passing in the event object, now we just need to update the state.
So, we can say this.setState and pass in the object, from here, this is gonna look a little weird, the syntax is. We need to know if it's an email or a password. You might think that, okay, I would just come up here and I'd say if event.something.name, that kind of thing. If it's equaling email, then I want you to update the email and then else, I want you to update the password, and that would technically work but there is a better way of doing that.
What we can do is we can dynamically change and pick the name that we're getting. So, the event has what is called a target. So, I can say event.target.name, and what this is gonna do is it's going to pick up the event that we got, this change event it's gonna pick up a target and then that target has attributes.
If you wanna come back, if you don't trust me, let's look at it. So, with this SyntheticEvent object, if I open it up, if you scroll down, you can see target.
So, target is an object here. Oh, and let's see, oh, and actually, it's empty right now so let's clear it. Let me comment this out and let's put the debugger, this is actually a great spot for the debugger, hit save. And now, hit refresh, and if I start typing anything in then it's automatically gonna fire this debugger, and so we can look for that event.
So, we can see that we got this SyntheticEvent right here and we aren't getting any changes, but if we come back, we can look for the target, and here we go, here it is.
So, we have target input, and then keep coming down, keep coming down, and you'll see that we have a name here eventually, there we go, and the name is email, so, that's where I'm getting that.
This object has a few nested properties and it's giving us this email. So, what we can do is grab that and you might think that, okay, I can do that and then put the value here, but we have one more step that we have to do. We have to wrap up this event.target.name in brackets.
So, because, if you remember, just whenever you create a normal JavaScript object, something like this, you have this object and you'd wanna say something like this is my key and then this is, whatever the value is. Well, if you're passing a dynamic name, so if you're actually getting this from a JavaScript primitive like what we have right here with this object, then you cannot just say the key, you have to wrap it up in brackets.
Then what JavaScript is gonna do is it's going to take whatever that value is and it's just gonna turn it into a string for us, and then it's gonna work. So, that's all you need to do whenever you're handling a dynamic value in an object.
Now that we have that, now we can say event.target.value, and that should set the email and the value. So, let's test this out and see if this is now working, I'm gonna close this off, hit refresh, and now, if this is working, it should now actually allow us to change. So, if I say asdf@asdf.com, you can see that now we're able to update the form and that is updating the state.
So, if you come back down here, let's just test this out here, I'm gonna create an h2 and say this.state.email,
hit save, and we can also do it for password. Now, we should be able to see these values, so I'm gonna clear this out and you can see that we have the value that I have right there, and then, I'm going to type some things out.
I'm hiding the password just so you don't see what my password is 'cause it is the same one I have for DevCamp Space. And so now, if I type something like asdf@asdf.com, you can see that that is working properly. If I type something else into the password right here, then that's being picked up.
So, I know that was kind of a long video and it is a little convoluted, but that is how we work with React forms. We have the input for this case, we have the input that has the value attached to it. That's how it knows what is inside of that input. And then, we have an onChange handler, and that onChange handler then is what we use to control our state.
In this case, we're taking state, we're setting it dynamically we're looking at the event, the target, and the name property. That's how we know if it's an email or a password. And if you ask yourself, why would we go through all these steps on learning this when we could just build a conditional? Well, imagine a form that has inputs, you would not wanna create 10 different conditionals.
I've done that for very large forms and these three lines of code right here are all I needed to do to capture the value and to update the state, just like we did right here. So, now that we have all of these in place, in the next guide, we're gonna talk about the handler we have for this submission process, and we can see the data that we're gonna have access to when we submit the form.