Check out a free preview of the full Complete Intro to React, v9 course

The "Uncontrolled Forms" Lesson is part of the full, Complete Intro to React, v9 course featured in this preview video. Here's what you'd learn in this lesson:

Brian demonstrates uncontrolled forms, which remove any custom state or input management from the form and leave the data processing to the submit event handler. A contact form is created. On submit, the form data is sent to the API server and a message is displayed in the application.

Preview
Close

Transcript from the "Uncontrolled Forms" Lesson

[00:00:00]
>> Brian Holt: Uncontrolled Forms, not just from when you feel out of control of your life. We're gonna talk about some uncontrolled forms. Alluded to a little bit on this Create Order page that we have controlled inputs here, right? That we're actually, explicitly using the value and we're setting it and we're using hooks to track everything.

[00:00:22]
As you might imagine, that's called a controlled form because we're using React to explicitly control the input and the output of the form. I will say that this is more unusual. I would say, usually, you wanna do what's called an uncontrolled form, which is basically, let the browser just handle all of the form stuff for you, and only listen for submit events.

[00:00:42]
This is pretty easy for us to just kinda knock out really quick. So let's go ahead and go do that. Also, wanted to show you how to do a post or a mutation with a TanStack Query. So we'll knock out both of those birds with one stone.
>> Brian Holt: Okay, so inside of your API directory, we're gonna make a getPastOrder, no, I'm just kidding.

[00:01:08]
We're gonna make a postContact file here.
>> Brian Holt: And it's gonna be export default async function postContact, takes in name, email, and message. And contact response, or const response = await fetch, and we're gonna post to /api/contact. And we have to give it some more configuration here, so we have to give it a method, which is going to be POST headers, as we learned before, definitely s headers.

[00:01:58]
We're doing Content-Type application/json, and the body is going to be JSON.stringify( name, email, and message). So if this is not apparent yet, we're gonna make a contact form, right, where someone can go in and put name, email, and a message, and then we will spam them with emails.

[00:02:29]
That's kind of my plan here in Brian's Capitalism 101. So if the response is not okay,
>> Brian Holt: Then we'll just throw an error.
>> Brian Holt: This is how you wanna handle this actually because that way, TanStack Query will actually catch the error for you, and then it'll set the is error property be true, and then you can handle that appropriately, right?

[00:03:04]
>> Brian Holt: And then return response.json. So this is an async function. So it always returns a promise, I think we talked about that earlier, that async functions always return. So what we could have done here is it said,
>> Brian Holt: Const json = response.json, and return json, that's typically what I've done.

[00:03:32]
But I got this code from TanStack Query, and they do it this way. And it's because if you return a promise, then it does something called promise chaining, that none of you ever have to think about that term ever again, but that's what it is called, where you basically do promise, then this.

[00:03:46]
And so if you return a promise, it implicitly chains that promise to the current promise. Not that really matters for you, but that's why it's okay that we're not awaiting here, cuz you could do a to return await response.json, but you don't need to, and it doesn't really make a difference.

[00:04:11]
>> Brian Holt: Again, stuff you just don't really have to care about. Okay, so let's go to index.lazy.jsx
>> Brian Holt: I feel like most of the stuff I learned from stuff like this is like, I'll look at a lot of line of codes like, why the hell does that work that way?

[00:04:27]
And then I'll get way too deep into it, that's how I found that one. Okay, index.lazy.jsx, we're gonna make a contact form. So we'll just make another one of these li's with a link into it. This is gonna go to contact, and we're gonna put a contact us or something like that.

[00:04:50]
>> Brian Holt: Okay, and then we're gonna go make a new route here. So this is gonna be contact.lazy.jsx. Get a nice little stub here from TanStack router.
>> Brian Holt: So that's all good, we need import useMutation from TanStack React Query, and we need our postContact from postContact. There we go, and then we'll make a function called ContactRoute, or page, or whatever you wanna call it.

[00:05:32]
And we'll just put that up here.
>> Brian Holt: Okay, now we have our React component, so now we're gonna do a mutation, which is just a fun way of saying, a post, or a put, or a patch, or something like that, but it's changing something. A query is in theory, you can call the query as many times as you want, it doesn't change anything, right, it's just getting data back from the API.

[00:05:56]
And a mutation, you don't wanna call that a bunch of different times because it could be semantically different depending on if you do it multiple times, right? I don't wanna get into the intricacies of rest, because, again, it is one of the dumbest things that people argue about is, should this be a put, or should this be a patch, or should this be a post?

[00:06:16]
And my answer to that is, it doesn't matter, just write the API, right, who cares? So TanStack kind of wraps all these things into the put, patch, delete, all that kinda stuff into a mutation, right, something is changing on the server side. So const mutation = useMutation, here a mutation function, function ee.preventDefault, right, cuz we're gonna use this as a form submit.

[00:06:50]
So, we'll have a preventDefault. We're gonna grab the form data. So, we're gonna say that by const formData = new FormData. FormData is a browser API, so this comes from the browser, it doesn't come from React. And we're gonna say e.target. E.target in this particular case, because this is gonna be a submit event from a form.

[00:07:15]
E.target will be what? The form, right? So the form element will actually be the e.target here. So when you do new FormData like this, it's going to then pull all this out into this FormData object, and we can now pull all of the information out of the form using this FormData API.

[00:07:34]
Okay, and then we're gonna return postContact, formData.get name. And we're gonna do that three times, once for email and once for message. Just to make sure we got this right, we're gonna look in postContact's name, email, message, get rid of that, don't save, and to look, again, in contact, name, email, message, right?

[00:08:16]
We gotta make sure that the things get put in there in the right order. Now, we have this mutation function, or hook that we can call. I always call that a hook, but it's like the result of a hook. This would be an object of some variety, what do they call it, the useMutation result.

[00:08:35]
This is the name of the type, and now this doesn't get called every time like query does, right? It actually waits for you to invoke it. So let's go check out how you do that. Let's go start building our markup for the page. We're gonna say, return here, and we'll start building our contact page.

[00:08:55]
Hk, h2, this is a contact, and then we're gonna say, if the mutation is successful, so if they successfully click Submit my contact. We don't wanna just leave them on the contact page, we wanna do something else, right? So we're gonna say, isSuccess. And if it is successful, then we're gonna say, h3 submitted.

[00:09:32]
In theory, you would have probably some nicer thing here, would be like, redirect them back to the home page or something like that, but I don't know, let them do some work, let them run it, okay? So otherwise, we're gonna show them the form, right, of something that they can submit.

[00:09:48]
So the form, and then we're gonna say onSubmit.
>> Brian Holt: We're gonna say, mutation., you're never gonna guess what the function's called, mutate [LAUGH]. So whenever the Submit happens, right, either by someone hitting Enter or hitting the Submit button, it's going to call this function, which as you guessed, is probably gonna go call the mutation function on this useMutation hook, right?

[00:10:26]
But not before then, which is cool. All right, we're gonna put a couple inputs in here, name = name. We're gonna have one for placeholder="name", and we'll have another one here for email. And it's a good idea as well to put type equals email, that'll bring up the different keyboard in iOS and Android, right, and it'll also do some basic validation is, is this a valid email, yeah.

[00:11:01]
>> Question 1: Why is it, for us calling a mutation .mutate, why does that automatically go to mutate.function and not us calling mutate.mutate function?
>> Brian Holt: That's a good question. So this is not actually directly calling the useMutation function here. It's actually calling something else inside of TanStack Query, which is doing a bunch of other stuff first, and then it calls your function.

[00:11:27]
>> Question 1: Okay.
>> Brian Holt: Yeah, so this is just saying, hey, whenever you're ready, call this function. This is the function that I've made to actually call the API, but there's some other machinery that it has to take care of first. That make sense? Cool, good question. Okay, so that's the inputs that we're on.

[00:11:43]
So email, email, email, the placeholder, we should probably make these capital because we're not savages, all right? And then we'll have a text area underneath this.
>> Brian Holt: Placeholder = message, and name = message. And that's good for that, and then we just want a button at the end that says, submit, button>Submit.

[00:12:17]
If you really wanna get explicit here, you can say, type="submit", but you don't need to, that's implicit unbuttons, right? But whatever, that's up to you.
>> Brian Holt: And cool, all right, I think this is pretty close to good to go. Just refresh the page here. We'll go to Padre Gino's, contact us, nice looking little contact form we've built out here.

[00:12:52]
So we're gonna put Brian, we'll put brian@example.com. And why do you have snake-fish pizza?
>> Brian Holt: This is disturbing.
>> Brian Holt: This is probably from the FBI. So we should be able to submit this now, submitted. And if we go look at your, you can see right there, this is now being logged in our API server.

[00:13:33]
And like all customer contact forms, it just gets logged then ignored. [LAUGH] But the point being here is, one, we did the mutation with TanStack Query, which is pretty cool. And we also did uncontrolled forms, which I'm gonna say, there's no reason that we would need to necessarily keep track of everything in a hook here, right, cuz we're not doing anything that's kind of reactive to that, we're not doing any sort of type ahead, or.

[00:14:00]
In the previous course, I did one with pet adoption. So you would set the cat to be the type of animal, and then you'd have to repopulate the breed list so it's reactive to what's happening in the first drop-down, also known as the double drop-down problem. That one, you have to do a controlled form because you have to react to the first one, right?

[00:14:19]
You have to repopulate the breed drop-down list based on what's in the first drop-down. But this one, you're just gathering all the form data and you're submitting it somewhere, uncontrolled form is how you wanna do that.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now