Intermediate Next.js

Form

Scott Moss

Scott Moss

Superfilter AI
Intermediate Next.js

Check out a free preview of the full Intermediate Next.js course

The "Sign-In Form" Lesson is part of the full, Intermediate Next.js course featured in this preview video. Here's what you'd learn in this lesson:

Scott implements the sign-in form by adding the SubmitButton component and triggering the signinUser server action when the form is submitted. An error message for incorrect username and password combinations is also added to the UI. The current code can be found on the "step/1" branch.


Transcript from the "Sign-In Form" Lesson

>> Scott Moss: And just to get some more reps, let's just go do the same thing for sign in. So it's mostly the same thing, it's literally just changing the word from sign up to sign in, so it's a duplicate. So I'm not gonna walk through it, I'll just kind of space it in there.

But just make sure our app works and our users can sign in, we wanna do that. So let's just go ahead and do that, I'm just gonna go to the sign in form. I'm gonna add my submit button here.
>> Scott Moss: I'm gonna make a label.
>> Scott Moss: It's gonna say Sign in.

>> Scott Moss: Just like that, and then I'm going to import the signinUser, I think that's what I called it. Sign in, maybe I didn't export it, let me go check. We didn't make it yet, let's go make it, cool. So if we go back to the actions auth file, let's make the one for sign in.

So, export signinUser,
>> Scott Moss: It's gonna be the same thing, previous date.
>> Scott Moss: Just gonna any that, formData. And that's gonna be type FormData, nothing crazy. Why did I put that there, I don't know. I'm trying to do something crazy, here we go, all right. So we got that, same thing, we want to validate the input, because, can't trust these users.

Do that, and then we just wanna try-catch. And the only difference with this one is, is the function that it calls in the try-catch, so we won't call the signup function. We'll call the signin function from the same import, from @utils/authTools.
>> Scott Moss: But everything else is the same.

You set the cookie, we show you failed to, I guess we'll change the message to failed to sign you in. We should actually test this, so, I want you to see the error message, so we'll do that too. So there we got that. Now I can import my signinUser like so.

I can get my hook going, which is gonna useFormState, pass in my signinUser, like that, pass in my initial state, which is gonna be the same as signup.
>> Scott Moss: And then I'll have my formState here, and then I have my action here, and then, on the form, action, action.

>> Scott Moss: And then, as far as showing some errors, I mean, there's no wrong way to do this, but I'll just do something like this. I'll say formState.message, if that's there, I'm gonna just do this, just in case. If that's there, then just show this message right quick.
>> Scott Moss: Which will just be formState.message.

I'm just gonna show exactly what the server actually returned.
>> Scott Moss: I'll just do that.
>> Scott Moss: You can also hook this up, if you're worried about accessibility, this is where you can take this message and feed it to a screen reader or something like that. Okay, so let's try to sign in, I'm gonna actually just break it, and hopefully, we can see that error.

So let's go back to sign in, that renders, give it a real email.
>> Scott Moss: Sorry about that. Then we can do that, and then, boom, you can see right here, it failed to sign you in. You might notice that the form didn't clear, right? If that bothers you as much as it bothers me, then we're the same type of people.

Yeah, there really is no easy way to do this. There is a way, and I didn't wanna put it in here, cuz it's a hack. The recommended way that I saw people do this on the server side is actually to pass a ref. Cuz once you pass a ref to the form, you can just do form.clear inside the server action, and that works totally fine.

But I didn't feel like writing, I didn't feel like doing this. Or you gotta do this, and then you pass in the ref, and then you make a ref, and then you add the ref. I didn't feel like doing that, so that's how you would do it. So once you pass in that form ref inside of this function, you would have, I don't know, maybe that's your third argument.

I don't know, wherever you pass it in, you could come down here and say ref.current, which will be the form, and all forms have a clear method on them. You could do that, and that's how you would clear. But that's so much work, I'm not doing that. Also, I want them to do better.

I want them to make a better one, so I refuse to do it that way. Make that better, I'm not using that, that's gross. And I know that they don't want you to do that. Or not that they don't want you to, I know that they haven't thought about it yet, because there's nothing in their docs, I had to figure that out.

I was like, that's just how you do it, there's nothing in their docs talks about that. So I think this is one of those things where they're waiting, I mean, Next.js, they're waiting for the React team to do something about it. So they're just like, I don't know, we'll see what the React team does, I don't know, but that's how you would do it.

If you are dependent on a response from a server action that calls an external API to change the UI, how can that response be taken care of when it's being inserted directly into the action attribute of the form? I'm guessing when they say taken care of, they actually wanna get the result of that response and do something with it.

Yes, that's a great question. And that example, you probably wouldn't use the action in the form. You would do what I'm gonna show you later, which is to use a transition where you can get the result of the data. But in the example that we do have, just to kinda fit it in, right now, we're just returning a message, right?

But there's nothing stopping you from, if I go here, right now, I can return whatever I want here, right? I could put the token here if I want, and it's there. So now, on the form, if there is a formState.token, that's the result. So you can check for it there.

We had a question about, can you take these exported server actions and unit test them? Yes, but with some caveats. Whenever you have this directive at the top of a file, not only is it expected to run in Node, which is fine for any unit testing framework like Jest.

Jest runs in Node, it's great. But it's also expected that these functions are running on a request. That's why we're able to access things like the cookies, and we can do things like the headers. So, with that being said, if you were to test these, you would most likely have to mock these out.

Because, again, it's expected that these functions are running on some type of request, because that's really what a server action is. They only get called when they need to cross the threshold from a client to a server, which is basically a request. So you just need to mock those out.

Whatever framework you wanna use just lets you mock out entire modules, things like that, you most likely have to mock those out. So, you can build an abstraction around this, do some dependency injection if you want, but for the most part, yeah, it's totally fine.

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