
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
Complete source code available till this point of lesson is available at
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
In this lesson, we focus on enhancing the front-end functionality of a question creation form by ensuring user authentication, handling question submissions, and implementing redirection to a question details page. We explore various aspects of managing route parameters and the difference between params and search params in Next.js. We also introduce the useTransition
hook from React for a smoother UI experience during form submissions.
useTransition
hook to manage loading states seamlessly during question submission, improving overall user experience.00:00:02 Now that we have the logic for creating a question, let's hook it up to our front-end form.
00:00:07 First, let's head over to the Ask Question page.
00:00:11 That is this page right here on the root Ask Question page.dsx, which currently only renders a question form.
00:00:18 We can add one additional check right here, and that is to ensure that only logged-in users can visit this form.
00:00:26 If I log out, head back to home, and then head over to ask a question, you can see that I can still do it, but that shouldn't be possible.
00:00:34 So let's simply say const session is equal to await auth, how simple that is.
00:00:42 And then we can simply say, if there is no session, we're going to simply redirect using the next navigation to forward slash sign in.
00:00:53 This will very quickly let all the users know that they have to sign in if they want to ask a question.
00:00:59 And that way your application will get more users in a reasonable way.
00:01:03 So now if you're logged out and if you head over to ask a question, as you can see, you just get redirected to sign in.
00:01:10 So let me sign back in.
00:01:12 And if I head over to ask a question now, I can see it just right.
00:01:15 Now, after we successfully submit a question, we need to redirect to the question details page.
00:01:21 So let's create a route for that page that's going to be under app route.
00:01:27 And we'll create a new folder called question.
00:01:31 Within that question folder, we'll create a new dynamic route called ID.
00:01:36 And within ID, we'll create a new page.tsx within which we'll simply run RAFCE.
00:01:44 This will be our question details page.
00:01:48 So let's call it as such.
00:01:50 And it looks like I missed the X under TSX right here.
00:01:54 There we go.
00:01:55 Now our editor knows that this is a JSX component.
00:01:58 For this route and many others, where we have a dynamic parameter, we have to somehow extract this ID to be able to fetch the details of that specific question.
00:02:08 And to do that in Next.js, we can simply get access to the page parameters through prompts.
00:02:13 And since we'll use this in many places, let's actually create a common TypeScript type for the route parameters.
00:02:20 I can do that if I head over to types, global.d.ts, and then right at the bottom, we can create a new interface, routePeramps,
00:02:32 which is going to be equal to peramps, which will be a promise since in recent times, we actually have to await the access to get those peramps.
00:02:42 And it's going to be of a type record, string, and string, like so.
00:02:49 This record string string is a utility type that defines an object structure or each property is a key value pair, both of which are strings.
00:02:58 And we can do the same thing for search params.
00:03:02 which is going to be of a type promise, and we'll again have a record of string and string.
00:03:10 Now, quick question.
00:03:11 Do you know what is the difference between params and search params?
00:03:14 Try to think about it while I write this example right here, just to remind you.
00:03:19 Params you can get access to by saying questions forward slash, and then you get access to that dynamic ID parameter, but search params come after the
00:03:28 question mark where you define the key value pair such as tag is equal to JavaScript.
00:03:34 So this is just forward slash some dynamic value.
00:03:37 And this right here is question mark key and value pair.
00:03:41 Great.
00:03:42 So we define both here so we can try to use them within our application.
00:03:46 In this case, we just need to get access to params, which will be of a type route params.
00:03:52 So let's try to get access to that ID by saying const ID is equal to await params.
00:03:59 And of course we have to make this function async for this to work.
00:04:03 Finally, we can say this is a question page of the question with this specific ID.
00:04:10 And I just noticed I have a typo right here.
00:04:12 This was supposed to be question details.
00:04:15 There we go.
00:04:16 Soon enough, if we have done the logic correctly, we'll be redirected to this question upon a successful question submission.
00:04:24 But now, let's actually go back to our question form to submit our question.
00:04:30 We can do that by implementing the logic of the handleCreateQuestion function.
00:04:36 So right here, let's say something along the lines of const result is equal to await.
00:04:42 We have to make the function async then.
00:04:46 And we'll await the create question action call like this, to which we can pass all the data, which we'll then validate.
00:04:56 If this results in a success, so if result.success is equal to true, in that case, we can show some kind of a toast coming from hooks,
00:05:06 use toast, and we'll give it a title of success, as well as a description of question created successfully.
00:05:15 And after the toast, we want to navigate over to the question details page of the newly created question.
00:05:20 So right at the top of the question form, Let's get access to the router by saying const router is equal to use router coming from not next router,
00:05:31 but rather next navigation.
00:05:33 And then right here below, below the toast, we can say router dot push, and we can push to forward slash questions, forward slash result dot data,
00:05:43 question mark dot underscore ID.
00:05:46 So we want to point to the details page of that specific question.
00:05:49 And it looks like it's saying that a question doesn't have its ID.
00:05:52 That cannot be.
00:05:54 So let's head over to our types, global.d.ts and search for the question.
00:06:00 And it looks like it's saying that a question doesn't have its own ID.
00:06:04 That cannot be.
00:06:05 Let's head over to the question.action.ts where we were creating that question.
00:06:11 And let's see what we said we would return from the create question action.
00:06:16 Here, we're returning the action response, but specifically the action response that contains the question.
00:06:23 So you have to do it like this.
00:06:25 And now it'll know that it actually has the ID belonging to a question.
00:06:30 Actually, it'll know that this entire result is indeed a question.
00:06:35 Perfect.
00:06:35 Now let's do another quick update and that is to move this statically typed thing right here into the routes utility.
00:06:42 So I'll copy it and I'll head over into routes, constants.
00:06:47 And if you check it out, it looks like we already had it.
00:06:49 This is going to be the question details page.
00:06:52 The only difference is that here I had questions and here we have a question.
00:06:57 Actually, I want to modify this one right here to say questions, because when architecting REST APIs, you always want to have the name of your collection
00:07:06 to be plural, like questions, and then you pass the ID of a specific question.
00:07:10 And now we also need to change the name of our page.
00:07:13 This is going to be questions instead of a question.
00:07:17 There we go.
00:07:17 That's much better.
00:07:18 Now we can simply call this route right here by saying push to routes.
00:07:23 And then you want to point to the ID of that question.
00:07:26 Now it's complaining that result data is possibly undefined and it's not lying.
00:07:32 It is.
00:07:32 Even though we're within this result.success, so we know everything went right.
00:07:36 Still, let's add another check.
00:07:38 If result.data exists, then we want to do router.push.
00:07:44 And now it won't complain.
00:07:45 It'll exactly know that this underscore ID is an ID belonging to a question.
00:07:50 Let's also do an else.
00:07:52 And here we can render a toast where we can render a title of an error.
00:07:59 And we can say something like result.status, as well as a description, which can be result.error, question mark.message.
00:08:07 Or something went wrong.
00:08:09 And finally, a variant of destructive.
00:08:14 There we go.
00:08:15 On its own, this should already do the trick.
00:08:18 But as you know, I always like to take you just a step further to test your skills a bit.
00:08:23 So in this case, I want to teach you how to use one of the new React hooks.
00:08:27 Use transition.
00:08:29 A hook that lets you render a part of the UI in the background.
00:08:32 Or in other words, instead of managing loading states manually to see whether your form has submitted or not, the useTransition simply gives you the isPending
00:08:42 state and the startTransition function.
00:08:44 It tracks the submission state more closely, reduces the boilerplate code, and one of the biggest advantages is that your work will be done in the background
00:08:53 and it won't block the rest of the UI interactions.
00:08:56 Using it is super simple.
00:08:58 Right here at the top, we can say const and then destructure the isPendingState as well as the startTransition function.
00:09:07 Make it equal to useTransition coming from React.
00:09:13 So this is a React functionality, not Next.js specific one.
00:09:17 And then you use it like this.
00:09:20 The only thing you have to do is wrap all the functionality we have here into the start transition.
00:09:26 So you say start transition, you create an async callback function within it, and then you can simply move all the code from here into the transition.
00:09:38 By doing this, what you get is access to the isPendingState, which lets you know whether you have successfully completed that transition or in this case,
00:09:47 the creation of a question.
00:09:48 Super simple.
00:09:50 Now you can head down where you have this button to submit it, and you can make it disabled if isPending is set to true.
00:09:57 And right here, you can say if isPending.
00:10:00 In that case, you can render some kind of a React empty fragment.
00:10:05 That'll include a reload icon.
00:10:08 coming from Radix UI React icons with a class name equal to margin right of two, size of four, and animate-spin.
00:10:18 So it actually spins around indicating that it's currently loading.
00:10:21 And right below it, I'll render a span that says submitting.
00:10:26 And then if we're not submitting, we can simply render the ask a question piece of text that can be within its own React fragment.
00:10:37 Perfect.
00:10:38 So this is it.
00:10:39 Like it very simply gives you access to the pending state by simply wrapping it in the site transition.
00:10:45 Could have you just created a regular use state and then track the loading progress that way?
00:10:50 Sure you could.
00:10:50 But there are advantages to using the use transition such as that it is not blocking the UI.
00:10:56 Because a transition can include multiple actions, and while a transition is in progress, your UI stays responsive.
00:11:03 So finally, let's test it out.
00:11:06 You can choose a question title.
00:11:08 In this case, I'll go with something like, what is the difference between debounce and throttle in JavaScript?
00:11:13 Just so we have some real code.
00:11:15 And this is another pro tip.
00:11:16 If you're planning on putting this project on your portfolio and showcasing it as a real app, besides creating a complete case study on how you started
00:11:26 creating it, the obstacles you encountered, and how you fixed them, that is very important to show to potential employers how you approach problems and
00:11:33 how you solve them.
00:11:34 And that is something that we dive a bit deeper about within our Dev Career Accelerator course, which I will link below.
00:11:40 But besides doing that, what I suggest is always have real sample data within your application.
00:11:47 Don't just put lorem ipsum, if you even know what that is.
00:11:50 That's been a very old way of just having some dummy text.
00:11:54 Or don't just put some dummy stuff right here.
00:11:56 Really try to think of something that your users would write right here, and that way your application, once you submit that question,
00:12:04 will feel more like a real application.
00:12:07 I've also prepared some kind of a detailed explanation of the problem here.
00:12:11 You can do the same.
00:12:12 And in this case, I'll do something like JavaScript as one tag, as well as performance as the second one.
00:12:20 And I'll give it a shot.
00:12:22 ask a question, submitting, question submitted successfully, and we have been successfully redirected to the question details page with its own ID.
00:12:33 And just to verify whether it all works successfully, I'll quickly check out my MongoDB.
00:12:37 Feel free to go to MongoDB Atlas as well, which would be totally okay, but I'll check it right here within Devflows.
00:12:44 And now we have questions where we have one document with that specific question, and it includes two different tags.
00:12:52 such as the ones ending with bad and bae.
00:12:54 This is interesting.
00:12:56 So now we can open up some different collection, such as tags, and we can see that two tags have been created, one that ends with bad and one that ends
00:13:05 with bae with the name of performance and JavaScript.
00:13:08 And finally, we can see the tag questions collection, which contains, check this out, connections between the question and the tag.
00:13:18 This means that we have successfully implemented the question and tag creation functionality.
00:13:24 Great work.
00:13:25 I will now submit this.
00:13:27 And you can see that I have some more file changes.
00:13:29 That's because in the meantime, I also updated my packages to make sure that this course is always up to date.
00:13:36 Don't worry if you don't have the same file changes here.
00:13:38 And I'll say implement create question form logic.
00:13:44 commit and sync, and we are ready to move to the next lesson in which we'll implement the edit questions action and then later on test the editing functionality
00:13:54 of our questions.
00:13:55 Great work.