Check out a free preview of the full Intermediate Next.js course
The "Events Page" 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 events page and creates a route to display an event by ID. The individual event page uses the params property to access the idea and load the details for the event. The behavior of the loading component with nested routes is also demonstrated in this lesson. The final code can be found on the "step/6" branch.
Transcript from the "Events Page" Lesson
[00:00:00]
>> Scott Moss: So the last thing we'll do, which is kinda just like, now apply everything you learn and go build this is, we have two more pages in our app that kinda needs some love. We really haven't done anything on them, and we really should. We should go fill these pages with all the data and the JSX they need.
[00:00:20]
So let's go in and do those, and that way we can kinda just apply all the things we just did on two different pages. So the first page is gonna be the events page. I already made it just on mind. It just says no, and actually it's gonna be three pages.
[00:00:35]
There's gonna be the events page where it list all the events. There's gonna be a event page where you can get one event by one ID. So we need to make some server functions for those two. And then there's gonna be a,
>> Scott Moss: An attendees page that lists all the attendees.
[00:00:54]
So that one needs a function too. So let's go do that. So first we'll go to the utils events.
>> Scott Moss: And we're gonna make some more functions in here. So the other function we're going to make is going to be, getAllEvents. This one's super easy. So getAllEvents. I'm just gonna go ahead and add my memoize now cuz I already know I'm doing it.
[00:01:27]
>> Scott Moss: And getAllEvents takes in a userId, which is a string.
>> Scott Moss: All it's gonna do after delay, of course, is the events.
>> Scott Moss: Equals await db.query.id, okay, after that, db.query.events.findMany. Where?
>> Scott Moss: Equals events.createdById is userId, like that. So that'll give us our events, and then just order by,
>> Scott Moss: Let's look at, what do I have here?
[00:02:22]
Ascending event start on. Okay, so let's say ascending events.startOn.
>> Scott Moss: So that'd be our query is just gonna go get all the events where the createdById of that event equals the given userId, and then orderBy an ascending order of events.startOn.
>> Scott Moss: So it'll show the oldest one on top.
[00:02:58]
>> Scott Moss: Okay, and then just need to return that. I'm just gonna get rid of the await and just return it I guess. And then we need to set up our cache stuff here. So I'm gonna say, persist true, that's the main one, and then revalidateTags.
>> Scott Moss: This will be events.
[00:03:25]
>> Scott Moss: And because we already have a mutation where we create events with that plus button and we revalidated that slot for the events, I also need to revalidate this page for the events. So I'm gonna go back to our events action file where we're gonna revalidate tag, I'm gonna revalidate another tag for events.
[00:03:49]
>> Scott Moss: So that page also gets revalidated when a new event gets created.
>> Scott Moss: Okay, we got to getAllEvents.
>> Scott Moss: Now we must go ahead and get the one for the get one event as well. This one's gonna be slightly different on the key for the revalidation because it has a event ID.
[00:04:17]
So we need to create a key based on that.
>> Scott Moss: GetOneEvent = memoize(async.
>> Scott Moss: And this takes in a userId and an eventId like that.
>> Scott Moss: And then this one's pretty simple, you just do a fine first where those two things match. So I'll await a delay and I'll just return db.query.events.findFirst where and eq(events.id is equal to eventId.
[00:05:13]
And then the other one is equal to events.createdById is userId.
>> Scott Moss: There we go, so I got that.
>> Scott Moss: And then for this other stuff, the cache situation, and say, persist true. And for the revalidation tags, this has a userId here.
>> Scott Moss: I would need that one, cuz here's the eventId.
[00:05:56]
Here, I do need that, so I can say, this is events, eventId. So we're gonna go to dashboard events page, .TSX. I think I already have it in mine, it just does no.
>> Scott Moss: Not to be confused with at events, just events, two different things. And I'm just gonna put this in here.
[00:06:16]
So this is gonna get the current user as always, it's gonna get all the events, the thing we just made. And just gonna put it here with the name.
>> Scott Moss: And then when you click on one, it'll take you to the event detail for that. So let's make a route for that.
[00:06:38]
So in events, we'll make a new folder, call it bracket Id. This is for our parameters. And inside of there, we'll make our page.tsx, like that.
>> Scott Moss: And then for this, I'll just grab this JSX.
>> Scott Moss: There you go. If you wanna get the incoming parameter for a dynamic route, it's always passed in on the params objects of the page.
[00:07:11]
It's always that. So it'll be params.id because I called it id here. If I called this anything else, this will be perams.anythingelse. So let's check that out, see if that works. Let's go to our events.
>> Scott Moss: Boom, boom, boom, okay, so that seems to be working, let's go to this event, see what happens.
[00:07:40]
There it is. The reason it took so long that time is because we're in dev mode and that that page didn't get compiled until I clicked on it. So you can see right here it took 307 milliseconds to compile that page cuz we're in dev mode, and the pages don't get compiled until you hit them at least once.
[00:07:55]
In production, that gets compiled before you deploy, so that delay would have happened. There still is going to be a delay, it just won't be that long. If I go back here, there's still, for sure, going to be a delay here. That was a delay in the data fetching, but the actual component is already compiled.
[00:08:16]
The reason that looks like that is we don't have a loading, right, it's just sitting there. We're not streaming this down, so I clicked it. Let's see how long it took because we didn't enable suspense, we didn't do streaming. So it's waiting to transition, to go. So you need to add a loading TSX to prevent that from happening.
[00:08:36]
So we can transition, show the loader, and then it'll come in, it'll stream in when it comes. So if you don't want that, add a loading TSX. So why did the events page, when you redirected it, why does that one have a loading?
>> Student 1: Is it picking up the dashboard parents loading?
[00:08:53]
>> Scott Moss: This events page?
>> Student 1: Yeah, if you hard refresh and reload that, it has a loader.
>> Scott Moss: It does, yeah.
>> Student 1: They don't have a loading.
>> Scott Moss: Do I have a loading here?
>> Student 1: No, cuz I don't have one and it's still doing it. So is it picking that up from the parent somehow, the parent layout, or?
[00:09:10]
>> Scott Moss: No, I don't think, I mean, we can test it out, let's see. I don't think so.
>> Student 1: Yeah, cuz it shouldn't be picking up.
>> Scott Moss: There is a dashboard, events loading page.
>> Student 1: Yeah, is it picking up from the ad events one?
>> Scott Moss: That'd be funny. Maybe it does go up to its, if it doesn't, no, I don't know.
[00:09:31]
>> Student 1: Okay, yeah, it is.
>> Scott Moss: Yeah, it is, it is picking that one up.
>> Scott Moss: I didn't know it picked up its ancestors. Then in that, I don't know, I think that's a bug.
>> Student 1: Okay, cuz then you'd assume that the ID one would also pick up the ancestors, but.
[00:09:48]
>> Scott Moss: Right, cuz it only goes one level up, doesn't go two levels up. That's kinda inconsistent. Yeah, that could very well be a bug. I've actually never seen them before.
>> Student 1: No, the ID won't have one too.
>> Student 2: Yeah.
>> Scott Moss: It does?
>> Student 1: When I hard refresh.
>> Scott Moss: Then, I know there's a way to do a global loading.
[00:10:05]
You specifically have to say, this is the global loading indicator, and that one will work for everything.
>> Student 2: Yeah, but if you hit the events page, cuz I've got the spinner for the events page. But if you click on the one, it does the dot, dot, dot loading, so it is using the one that's down in the [INAUDIBLE].
[00:10:31]
>> Scott Moss: Actually, I know what's happening here.
>> Student 2: Yeah.
>> Scott Moss: This isn't the look, I think, let me see. Hold on, I think what's happening here is Expand events. What we're seeing is, we're not seeing the loading for this. Okay, we're actually seeing the loading for the page because, check out the layout, right?
[00:10:54]
The layout will load the children, okay, when it's not in dashboard mode. So I think what we're seeing is because we go to slash dashboard slash events, we're gonna see the loading here no matter what. Whereas in these examples, these things have their own loaders. But if you look at the layout,
>> Scott Moss: Here.
[00:11:24]
These things are rendered in their own slots, but here's just one child. So think it's just picking it up that way, specifically because,
>> Scott Moss: [CROSSTALK] I still would imagine to do that.
>> Student 3: Expand your Id there once.
>> Scott Moss: Yeah, actually, let's do this.
>> Student 3: Wait, you don't have a loader here.
[00:11:42]
>> Scott Moss: No, I don't have one, let's make something, let's do one. Let's see what happens here, I'm curious now.
>> Scott Moss: So to here.
>> Scott Moss: Okay, let's try that, am I in the right? Okay, I'm in the right there. Let's see what we have first. [INAUDIBLE] Yeah, okay, I guess it just picks up its parents, it's grandparents, its ancestors.
[00:12:18]
>> Student 4: Yeah, but then you could put a loading down in the Id bracketed area.
>> Scott Moss: Yeah, put one there, okay.
>> Student 4: Well, and actually in your main branch, you got one there.
>> Scott Moss: I do.
>> Student 4: Yeah.
>> Scott Moss: Okay, and that would make sense, yeah.
>> Student 4: And so when you click on the individual one, it uses that.
[00:12:41]
So now if you can say event, right? There you go, and then you click on one.
>> Scott Moss: Yeah, that makes sense.
>> Student 4: Yeah.
>> Scott Moss: That is interesting, let's see, let's do this together, I wanna see something right quick. Let's go to the docs.
>> Student 4: Do you like that?
[00:12:58]
>> Scott Moss: No. With the way suspense works, I think that's kinda the behavior of a suspense boundary if you were to do that manually. Yeah, cuz that's what I was trying to figure out. I'm like, it's wrapping the whole tree. It's like a boundary, yeah. But the way the routing works, it shouldn't [LAUGH].
[00:13:17]
>> Student 4: I think it's like a different page.
>> Scott Moss: You know what? I think what I was trying to say, and I think it just came cuz I lost my train of thought. I think the loading wraps, no, it doesn't say, wraps the layout, which would mean, yeah, everything would have the same loader, but I don't think it wraps the layout, I thought it wraps the actual page.
[00:13:37]
So-.
>> Student 4: Which is interesting, because that page renders the count, doesn't it, technically?
>> Scott Moss: Yeah.
>> Student 4: The dashboard page renders the count, but it's not in this because it's a different page, but it's still using that loader. So I thought they were tightly associated where that loading was for that page, but it seems like it can also be used for children.
[00:13:55]
Right, that is interesting.
>> Scott Moss: I don't see any mention of global or anything here. Now I'm just super fascinated about that parents, maybe. No, something new, pretty cool. That's actually a really cool feature.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops