A second and third version of this course released using Next 13+, but this course is great if you want to see another example fullstack project. We now recommend you take the Build an AI-Powered Fullstack Next.js App, v3 course.
Transcript from the "AuthForm Component" Lesson
>> So now we're going to do the auth form component, which is going to be the form that sits on our auth pages like register and sign in. But it's gonna be a flexible component because if you think about the auth form, whether you sign in or sign up, it's pretty much the same thing.
[00:00:16] We definitely have to email a password for both. And for our case register. If we go look at the schema A user must have a first name and last name. It's required. There's no question mark here. So we were probably asked for that on sign up. So register.
[00:00:32] So the only difference between register and sign in is that register has a first name and last name field. Other than that they're all the same. And whatever button you click on is different, so we can kind of just make one component to handle all of that use case versus making two separate components, in my opinion.
[00:00:49] So that's what we're gonna do. All form is just gonna handle all of that and depending on what property you pass it, it'll know how to toggle itself. Does that make sense? Cool. Let's do it. Okay. Just like I said, it's going to be a client component because it's a form and I would really love for someone to show me a form that's a server component because that would be crazy.
[00:01:15] I would like to see that. So our form tsx. Got a lot of things to import up here, but the first most important thing is use client. Do not forget that. Then we gonna import our input. We're gonna import our button. We're gonna import our card. What else do we have?
[00:01:44] We got our link, we got used router, we got everything in here, okay. So we're gonna import, use router from navigation. There's, a Next router on Next.js 12 that has use router. Do not import that one. You wanna import use router from Next navigation, which is new. I made that mistake before.
[00:02:06] Do not import, use router from Next router. That's pretty much being deprecated in favor of Next navigation. Okay, got that? We're going to import those register and sign-in utility functions we just made. It seems like alphabetizing like it's sorting my imports. What is this plugin? I've never seen this before.
[00:02:33] It's just like, decided to work today. It's like I'm gonna work today. We're gonna use callback. And we're also gonna use state. Remember that? And I think that's pretty much all we're gonna use here. So first thing we're gonna do is because this thing can toggle between two different modes, register mode, or sign-in mode, I'm just gonna make an object to represent all the different things between those modes.
[00:03:04] So I can just toggle the objects depending on the mode that you pass. So basically, I'm going to think about all the things that are dynamic in this form that change depending on what mode you have. And I'm going to put them in here. So all the things that are dynamic depending on whether it's in register mode, or sign in mode is going to be the URL that you click on, because there's going to be like a little thing at the bottom says I already have an account or I don't have an account.
[00:03:30] And I need that to be a different link whenever you click on it. So that's the link URL. The text for that question is gonna be different depending on what mode it's in, The header so the title of the form is gonna be different depending on what mode it's in.
[00:03:44] The sub header, the text underneath it, is gonna be different. And then the button text when you submit the form is gonna be different. So these are all the different things depending on the mode. So I assigned it for what looked like and what it, what it should look like for the register content and what it should look like for the sign in content.
[00:04:00] So that's what we're gonna do. So I'm gonna say const register content, and it's just gonna have like this link URL. And that's going to go to sign in if you already have an account. If you're on register, it's going to say already have an account. And the link text is basically that.
[00:04:24] Already have an account. All right. Header, sub header, and button text. So header, you can have it say whatever you want. I think I have created a new account. And then sub header. Don't get cheesy here, okay I got cheesy here. Just a few things to get started.
[00:04:49] Give me your credit card number. Button text and that's just going to say register. Cool, and then we'll do the same thing for if it's in sign in mode. When you click on this one, on the link at the bottom, it's actually gonna take you to register. And it's gonna say, instead of saying already have an account, it's gonna be what do I put here?
[00:05:17] Don't have an account? There you go. At the top, instead of saying create a new account, it might say something like welcome back. And that should be a lowercase a that's bothering me. And then subheader, I just have your credentials, getting your account. Nothing crazy here. And on this, they'll just say sign in.
[00:05:42] Cool. Then it's going to create some initial state. I'm creating it in an object out here. So if I have to reset the entire form, I can say reset to this object versus resetting these property. So always create an initial state outside so the email. It's gonna be a password, it's gonna be a first name.
[00:06:07] Sometimes if it's register mode, and then last name sometimes. There we go, that's the initial state. Now we can make our components, so auth form, Boom. And it's gonna take a mode, that's gonna be like sign in or register, and you can see I typed it here if you wanna do some type stuff.
[00:06:37] First thing is I'm gonna make my states. I was gonna say form states, you can call it whatever you want it should be an array. It's been so long since I used state, I forgot what it feels like. Set form state equals use state initial value there. And then what I want to do is, if you want to keep track of errors and do things with the errors, we can do that.
[00:07:15] I don't know if I'm actually doing anything with the error, actually. I think I was going to, then I was like, it's just client-side error handling, it's nothing really crazy, so probably not going to do anything with it, but it was there. Const router equals use router just like the other one from Next router.
>> Looks like you didn't include the spread operator before initial in the state and use thing all right here.
>> Yeah. Like this oops I like that. You said I should include the spread.
>> Yeah, I thought you did.
>> Did I? And the code example. Yeah, I think I was just being safe there.
[00:07:59] I just didn't want to think about objects, especially with React. Because objects are passed by reference. I just didn't know if React was like, I'm just gonna take this reference and run with it and do something, and we have side effects. So I was like, to avoid that, I'm just gonna make a brand new object and spread over it and give it a copy so it doesn't interfere with this original one.
[00:08:20] So it was just me being safe, but I think React is smart enough not to go ahead and mutate whatever I pass here for some initial data. I felt more confident today, than before when I wrote it. So. Sometimes you just gotta be safe. You just wanna avoid object mutations as much as you can react, especially on the client side.
[00:08:40] It's just, I mean, ask Angular one. That's what happened. [LAUGH] that's, [LAUGH] that's basically what you're leading to. So okay, so we got that. We got our router, we're going to say const handle submit. There we go. What are events? E dot prevent defaults, prevent this form from reloading our page, default.
[00:09:12] That's what it should be called. And then from there, all we're really gonna do is this is gonna be a async function. I have it wrapped in the used callback here cause I'm just over optimizing on reinders. And I mean, you could do that, you don't really have to do that.
[00:09:26] But all the used callback is doing is making sure that unless one of these things change, just use the same function across remainders, but that's just such an over optimization. It doesn't really matter. What does matter is though that this is an async function and depending on the mode, we're either gonna register or we're going to sign in, and then we're gonna route you to /home.
[00:09:52] And that's really it. So let's do that. So we're gonna say, If mode equals register, then we're going to await register with form state, if it's not registered must be the other one. So we're going to await sign in form states. And, we can try catch all of this, if we're gonna handle errors, and do things like that.
[00:10:27] But, we're not really handling errors, I mean, it's just setting an error and we're not really doing anything with it, because error handling on the front end, I think it's unique to whatever. You're like, you might show a toast, you might show a message underneath an input, you might show a modal, you might show an alert, there's an infinite amount of possibilities and there's nothing new that Next.js is contributing to it.
[00:10:50] So I didn't feel like it was worth even going there, but you could do whatever you want with that error handling. I think it's more powerful to explore errors on the server and server components and how that. So we have that and then after all of that, finally we just want to set form states to initial like that.
[00:11:15] Cool, so we got that. And then see all this JSX. Down here. Yeah, we got to write all that. But first we need to get the content object. So which one is it? Is it this one or is it this one? Well, that depends on the mode. So we'll say content equals mode equals register.
[00:11:36] Cool is the register content else. It's the other one. There we go. And then finally for the JSX, which is a lot, it's mostly styling. There's some logic here, but there's really nothing new in here that you don't already know if you've ever used React with a form, I'm not doing anything different, but we can walk through it.
[00:11:55] So I'll paste it in there though. Really the only important stuff in here that's not new, or that is new is really nothing. We're just all we're really doing here is we're using our input components. We're controlling them with the value. We're using it on change that value that we're controlling.
[00:12:22] One thing that might be different here is I think that most people when they make a form with multiple fields they'll have multiple use states, they'll have one use state for each field and that's fine, you could do that. I have one use day for the whole form.
[00:12:36] But the downside of that is whenever I go to set the form because the state is immutable whatever I pass to set form state will override the entire state so I have to be careful to pass the previous state first and then make my change here after. But if you are ever going to change state that is based off of a previous state, you must pass a callback to get access to the current state.
[00:13:06] If you don't pass that callback, and instead you reach for the current status form state you're not guaranteed to get the current state. You might be lagging behind. You might be lagging behind the rendering of React. It's not guaranteed. There's a good chance you will get it. But in a high performance scenario, like, I don't know, a Google Doc editor with multiple people typing, you might actually be behind a few renders if you just access form state to create a new state based off of it.
[00:13:31] So its always important to do this callback because setting a state is asynchronous in React. This guarantees that you get it after it's finished. Everything else is anything you've ever known and react when it comes to setting a fire. So nothing crazy there. The last thing is just to route you home.
[00:13:54] So we can say router.push or replace might even be better here. Push is adding a new route to the stack. So if they hit back, they can go back. Replace is sort of adding a new one to the stack, replace the current route that I'm at with the one that I want to go to so they hit back they can't, because it was never there.
[00:14:15] So this is like basically preventing someone from hitting back to go back to the sign up form after they already signed in, basically that's all it's doing. It's just basically you can't hit back to go back here. Okay, and then we're going to export this Okay cool. Any questions on the auth form?
>> Just a quick fix initialized on line 26 is spelled wrong. Still function correctly since you used it correctly on line 29, but just keep an eye after the end.
>> Which one?
>> Both of them are spelled wrong.
>> They're just both
>> Yeah, dang.
>> [LAUGH] some words.
>> I still didn't see it looking right at it. There we go. You'd think I would know that the company I work for is literally initialized [LAUGH] so every time I type that out I'm like yeah, it's about those many Is in one word. I'm like, looks suspicious.
[00:15:33] I don't know. So any questions?
>> I'll add that if you're using objects and state like that a lot I noticed in the official React docs that they recommend using a package called immer that handles that for you. Immer is so beautiful. Yeah I love immer. Immer basically turns immutability operations into this dot root scope that's basically what it does.
[00:16:00] It's so good it basically instead of doing like what I did with this it'll just be like. I can now just do something like, sdot, I can just say formState.FirstName equals whatever I want. And it will take that and do this for me. Yeah. Which is really cool.
[00:16:25] Yeah, I love immer. I actually use it all the time. I couldhave used it here. It's not too complicated here but when you start getting to arrays and you're like, I gotta find and find this thing in the array and update it and replace it like okay, I'm using immer for this.
[00:16:38] This is stupid. This is ridiculous. But yeah, I do love immer. That they should just bake that in, honestly.