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.

Check out a free preview of the full Build a Fullstack App with Next.js, v2 course:
The "Fetching Project Data" Lesson is part of the full, Build a Fullstack App with Next.js, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Scott explains why data fetching needs to occur in the parent containing the project cards and not in each individual card. Project card data is fetched in the application. The database is reset and reseeded so the seed user's password is hashed.

Get Unlimited Access Now

Transcript from the "Fetching Project Data" Lesson

[00:00:00]
>> So we got our project card. The next thing we need to do obviously bring it in here. We just got to figure out, how do we get the data for the projects, though. So let's think about this. Let's talk about the different use cases. So let's talk about this one first.

[00:00:15] Where did we get the data for this greeting card? The bigger the data in the page, the bigger the data in the card itself. You sure? Let's see, let's go to the greeting, uh-huh. We got the data and the component itself. The data responsible for the greeting card is in the greeting card itself, itself contained, and we didn't get this in the page.

[00:00:45] We could've, there's nothing wrong with that. We totally could've gotten the data from the page, pass it down as a prop, and it would've worked, but we would not be able to do this. We would not be able to see it loading like this independently because its data would have been bound to the page and that data would have got fetched when the page loaded.

[00:01:04] Whereas now, the data requirements for this component is not bound to the page, it's bound to itself. So the page and this component can load independently from each other.
>> And that's gonna be true for all the components. Or that's the idea.
>> That's the idea, exactly. The idea is to push the data fetching requirements down as far as you can to the component that needs it and do it there.

[00:01:27] That way you can load them individually from each other versus making the page have to wait for all of its children to load just to show something. We want to show something meaningful immediately and everything else can show up when it's ready, you just handle it with a fallback, with a loading page or a suspense fallback and you have these nice, for lack of better words, reactive, you know, apps.

[00:01:53] It's not new, people have been building apps like this for a while. It's just a lot of setup to do it. So it's quite a lot having to do it. Like you have to use something like, you know, finite state machines or something like that for your UI to really hone that in and that's so repetitive and redundant even though I do like using them.

[00:02:14] Okay, so we had to get the data and the greeting card internally, but for the project but but that makes sense because there's only one greeting card and it's always the same, but for the projects, each one of these products are different and there's gonna be many projects on the screen.

[00:02:32] So would we be getting the data for the projects in the project card itself? Or rename it, the project card singular. Would we be getting that in the project card itself? Or what would we have to get that somewhere else? Have to get it somewhere else?
>> I think it's in the card.

[00:02:52]
>> Think it's in the card?
>> Where you described it earlier.
>> Okay, so let's walk through that. So if we were to get the data for the project card in the project component,
>> You've got to generate project cards. We've got to generate project cards. So how would we do that?

[00:03:08]
>> There's many of those.
>> Yeah. So because of that, we'll have to probably do it on the page because only the page, the thing, the container that's responsible for laying these cards out, needs to know how many cards to lay out. So, therefore, this container as in this page, is probably going to hold the responsibility of getting the projects.

[00:03:31] Because each one of these projects doesn't know that there's more projects to go next to it and it doesn't have control over, like this project can't put this project next to it. But this this page can, this layout can. So because of that, the page itself will probably be doing the data fetching for the project which is different than this one.

[00:03:50] This one didn't need the page. This greeting card didn't need the page to do the product, the fetching for the data. Because it's self contained it knows that it needs data it doesn't need to be aware of another one next to it or anything like that, it's just one.

[00:04:04] So it's totally fine but in the case of this one where we have to loop over them and put them on the page. The page is the one I mean think about where you're gonna do the map. If this was an array of data, where are you gonna do data dot map?

[00:04:15] Is it gonna be in the individual card? Or is it gonna be the thing that's containing them, right? So unless we make another component that wraps all of these and put the data fetching in that, which we can, we'll have to put it in the next pair, which in this case is the page.

[00:04:30] Does that make sense? Okay, let's do that. So we're just gonna make get data, that's kind of the thing that I'm following here and we'll just have to do a query here. And then we can use that inside of our page. So let's go to our page inside of dashboard Our dashboard home.

[00:04:59] There we go. And we're going to make a function called getData. It's going to be async. We're going to await a delay. It'd be super dramatic here. And let's just delay for like, two seconds. And then imagine this was an API route that was protected. And someone was trying to get data.

[00:05:32] What would be the first thing you'd have to do before you went to the database to get them to get their data?
>> Check, make sure they're authenticated.
>> Exactly. We've got to check to make sure they're authenticated. So that's what we're gonna do. We're gonna use our getUserFromCookies, so we'll say user = await getUserFromCookie and pass in cookies.

[00:05:57] And notice we had to do this the same way in the greetings. We have to do that here too. So in a lot of these fetching functions that you'll use for your server components that are on protected pages, you'll find yourself authenticating the user most of the time which if you think ahead you can just build a higher order function for this.

[00:06:19] You could do something a little, just be like with auth, you just wrap everything, right and that'll do it for you. I'm almost positive that's what people are gonna start doing. But for us, we're just using a function. So we got our user. The next thing we wanna do is we wanna get all the projects for the current user, right?

[00:06:48] So we can use Prisma for that. So we can say, projects = await db.projects. It's still crazy the fact that I'm writing a database query, and a component at it, still blows my mind right now. And then we'll say findMany, like that, where we use where clause here.

[00:07:12] And basically, we just want to grab the ones that whose owner is the one that signed in and make sure we include tasks cuz we need tasks to be able to compute this stuff down here. And by default, it won't include tasks. So let's do that. So we'll say where owner ID is user ID.

[00:07:35] Right? This is just freaking out because it's like this is probably no and that's why I put that question mark there. And then we just want to include tasks. True. So now we got our projects. And then we just return the projects. I guess I had it in an object there, so I'll be consistent and do the same thing.

[00:08:07] I think this is a good practice, because this is simple but I would imagine you will you might have more data needs other than just one query. You might do a lot of stuff in here so you can send them all back here because I mean I guess you could also just make more functions and just call all of them here, but then we get into parallel versus serial data loading.

[00:08:27] And we could talk about that in a production V2 version of next JS, where how to optimize parallel async data fetching and server components versus serial and when to do it and how to do it. It's basically like a prefetch but for data, it's kind of crazy how that works.

[00:08:45] But we can get into that later because it's kind of complicated but for now, yeah, I'm just going to do that and then we can get our projects. Equals awaits get data like that, we've got to restructure this structure this. And now that we have our projects, by the way, don't forget to destructure.

[00:09:10] I didn't put that here, but you gotta destructure it if it's an object like that. Now that we have our projects, we can just loop over them and create this link for them around a project card so we can actually click on them. So let's do that. So if you go down to the JSX you can see right here it says projects map here, so you just want to put it here.

[00:09:32] So you can just say, projects.mapGet a project. And then we're gonna have a div here and inside this div we're gonna have a link and then inside this link we're gonna have a project cart. We go, okay. For the div we got some classes here we got a 1/3 and a p3.

[00:09:59] So we'll say class name with is 1/3 padding is three. On this link, we need a href. href is going to be dynamic cuz it's going to go to, look at the URL here. It's going to go to /project/ID. So we'll say /project/project.id. Like that. And this project cart takes a project Like that, and this is freaking out because it wants me to put a key.

[00:10:37] And I'll do it just so it goes away cuz it's annoying. I'll just do a project.id. Cool, now we have our projects. So let's go check it out and see what happens. Do we actually get some projects here? Loading, loading, loading. I didn't get any projects. Do I have projects here?

[00:11:08] Maybe I don't have any projects. Let's see. I'm going to log that. So it didn't error. Yeah, it looks like I just don't have any projects.
>> Yeah, we want to sign in through our seed user.
>> Yeah. I need to sign in through my seed user. I guess I'll do that.

[00:11:25] Let me do that. Let me go. To sign in try to sign in there I think it is what user at email and I think it's password, maybe. I don't think it's gonna work. Now, I see Alex is gonna work now because it's trying to like, it's trying to re-save the password.

[00:11:51] Yeah. Not hashed. But now it's trying to compare to hashed. So we got to go back into the seed and just hash the password. And that makes sense. Go down here and hash this. I'm gonna run my seed again. There we go, so I'm gonna create a database so that the hashing of the passwords in our seed script actually goes through because of the up cert.

[00:12:22] So mpx prisma migrates, let''s see help. I wanna say it's resets, but yeah, migrate reset, which I think runs the seat for us as well. If not, we'll just run it again after. Yeah, so it's running the seat for us. Okay, cool. Password, looks like it was hash.

[00:12:51] So let's start this thing. It's already stopped and started again. And let's go check it out. Where is it? Bring it over here, okay? So if we go to sign in Or sign in, there we go. Let's try to sign in with our seed user. There we go.

[00:13:30] It's trying to do something, there it is. So it's because we have that delay on the projects. That two second delay. Okay, so now we're in it looks like our projects are loaded up somehow we got 10 out of 10 completed. How lucky is that [LAUGH] with the randomness but that's the way it's seeded.

[00:13:49] I guess or math is wrong one of the two.