Build a Fullstack App from Scratch with Next.js by Scott Moss | Preview
Aug 15, 2023
Build a Fullstack App from Scratch with Next.js by Scott Moss | Preview
Full Course: Build a Fullstack App from Scratch with Next.js: https://frontendmasters.com/courses/f … About this Course: Create a full-stack Project Management app from scratch in Next.js. See how all the pieces of Next.js/React fit together: client components, server components, file-based routing, dynamic routing, middleware, and layouts. Along with Prisma and PostgreSQL for the database, TypeScript, to deploy your app to the world! Find Frontend Masters Online: Twitter: https://twitter.com/FrontendMasters LinkedIn: https://www.linkedin.com/company/fron … Facebook: https://www.facebook.com/FrontendMasters Instagram: https://instagram.com/FrontendMasters About Us: Advance your skills with in-depth, modern front-end engineering courses — our 150+ high-quality courses and 18 curated learning paths will guide you from mid-level to senior developer! https://frontendmasters.com/?utm_sour … Sections: 0:00 - Introduction and Course Description 0:38 - Setup Database Schema with Prisma 4:52 - Custom Hooks 13:14 - React Query
Content
0 -> [MUSIC]
8.109 -> Hey, how's it going?
8.82 -> I'm Scott Moss and
I've been an engineer for over a decade,
11.804 -> since before they were
full stack frameworks.
14.158 -> Today, I bring you how to build
full stack apps using Next.js, V2.
18.124 -> In this course, I'm gonna teach you
about all the new features that react 18
21.849 -> introduces, I'm talking client components,
server components,
25.182 -> and how Njs takes advantage of those
things in such a beautiful way.
28.417 -> File-based routing, dynamic routing,
middleware, layouts, I had so
32.478 -> much fun getting to know all
the cool things about Njs, and
35.635 -> I can't wait to share them with you.
37.649 -> If we just take a quick look at what we
have here, it's not a complicated schema.
44.376 -> I mean, it's gonna be a pretty simple
project task management app where
49.471 -> we have a user and a user has projects and
those projects have tasks.
54.242 -> And that's mostly it.
55.293 -> There's a lot of relationships between
the three, but that's mostly it.
58.406 -> So what we can do now is we can
go ahead and create this user.
62.068 -> So the first thing I'm
gonna do is make an ID and
66.146 -> go through and
kinda get all the other stuff in there.
70.863 -> So you can say model user.
73.518 -> You can say this is an ID.
75.116 -> It's a type of string.
76.449 -> You can also do integer if you prefer and
have your user IDs be numbers.
81.887 -> I don't like that so I'm gonna say string,
86.465 -> then I'm gonna say this is an ID,
like that, and
91.536 -> then I can say default and
I'm gonna use uuid.
96.379 -> So this is just basically making
the user IDs strings of type uuid,
101.547 -> a uuid is a type of universally
unique identifier it's a formatted
106.718 -> string that looks a certain way, that's
pretty much guaranteed to be unique.
112.929 -> That's what you ideas.
114.324 -> So, I'm making my user IDs UIDs.
117.8 -> Say created at, was just gonna be a date
time, and it's gonna default to now.
129.946 -> Then I can say updated at,
that's also gonna be a date time and
133.727 -> then there's a special updated that,
so we don't have to touch it.
137.97 -> It just updates that field for
140.664 -> us automatically whenever
we touch this model.
145.094 -> Okay, then you're gonna have an email
which is gonna be a type string,
150.974 -> first name, which is also a string.
154.012 -> A last name?
157.109 -> We have a password.
161.7 -> Password.
163.55 -> That's a string.
164.848 -> What else do we have projects and tasks?
168.442 -> We'll get to that in a minute
when we do relations.
170.249 -> So for user, for the most part.
172.729 -> That's pretty good.
174.626 -> So then we'll keep it moving,
and we'll say, model project, and
179.44 -> we can just copy these first
three things here, put them here.
183.924 -> Everything's gonna have an ID or
created app and updated app, so
186.679 -> we just put that there.
192.307 -> And a project has a name, that's a string.
197.202 -> What else would a project have,
it might have like a status, No,
201.23 -> we have the owner stuff.
202.725 -> Yeah, so a project will also
have who owns the project?
206.579 -> Who does it belong to?
208 -> If we don't have this, when we do a query,
210.633 -> we won't know what project belongs
to the user that's signed in.
214.743 -> Was beginning random people's projects.
217.92 -> So we can say, owner ID like this and
that's gonna be a string,
224.356 -> then we can say,
owner is going to be a user, like that,
230.064 -> and then we can say it's gonna
have a relation with these
235.771 -> fields of Owner ID that maps to
the reference on the user ID, like that.
243.083 -> And it's still gonna throw me
this little error here, basically
248.02 -> what this is saying is I wanna have
an owner filled whose type is user and
253.314 -> it's related to a user ID and
it maps to the owner id over here.
257.999 -> So this owner id is gonna to
map to the id on the user, and
260.695 -> he's freaking out right now,
he's like, hey,
263.158 -> you gotta go to the other side is
relationship and add something there.
266.701 -> And we could do that, but I'm really
lazy so I'm gonna do it the lazy way,
273.502 -> you can run MPX Prisma format and
it'll do it for you.
278.458 -> So I did that and you can see right
here it added project, project.
282.098 -> But, I'm gonna lowercase that and
call it projects
284.816 -> plural because it's an array of projects,
it's a one to many relationship.
288.917 -> So I'm just gonna change that to projects
and keep it the type project array.
292.814 -> We should think about how our
page is loading up right now,
296.035 -> we have a few things on here.
297.627 -> So we have this.
301.061 -> That's taken forever to
load because of the delay.
303.03 -> So that delay,
then we have this component coming in.
307.1 -> We kinda wanna handle this delay because
we're about to add this task card on here.
310.911 -> And that's gonna have another requirement
for data fetching, although it's not
315.02 -> blocking the page like projects is, it's
gonna be more how the greeting card is.
319.08 -> It'll just render when it gets there.
321.026 -> But that delay right there,
323.18 -> that strong delay while it's
loading right here, this one.
327.852 -> Yes, we see the projects here because it's
cached, but it won't always be there.
333.627 -> It's just because it's cached and
I'm on local hosts and whatnot.
336.335 -> So we should probably set up a loader for
this page.
340.802 -> So what we'll do is we'll
go to App Dashboard,
346.466 -> and then Home, right next to page we can
351.137 -> make a loader, or loading.tsx.
355.253 -> So, all this is gonna be
just your classic loader.
359.048 -> Whatever you wanna put a spinner,
the word loading,
361.939 -> doesn't matter, I did make one for
us and we could talk about it, but
365.664 -> it's mostly just using Tailwind so
I'm just gonna paste it in.
369.154 -> And it's just a loader.
372.848 -> It's just using the Animate
spin on a circle with a dash
377.379 -> border sitting in a cart.
379.555 -> That's all it is, it's nothing crazy.
382.299 -> So we have that now and for
free if we just load up our page.
385.574 -> [BLANK AUDIO].
389.016 -> We should see a loader like that now,
right.
393.314 -> That's because the projects
we're loading in.
396.937 -> The project has like a two second delay or
whatever delay on the projects I forgot,
401.383 -> but that's why you see that.
403 -> And then when we get in,
we see the greetings take four or
408.614 -> five seconds to load and
because of the delay on that.
413.998 -> Right, so you literally get granular
control over what's loading and
417.81 -> how it's loading and what's blocking and
what's not blocking.
421.379 -> And then for the task page, if I guess
forgot to put a slide for it in here
425.745 -> because we can just add it to the project,
there's nothing really special.
430.57 -> So what we'll do is just
go to the home page,
434.405 -> scroll down to where it says Task Here,
get rid of that,
439.277 -> and you could just bring in a task card.
446.969 -> Did I export mine,
I forgot to export mine.
458.311 -> >> Here we go, just bring that in.
460.905 -> It's safe and see if anything broke.
468.357 -> Boom, there we go.
469.284 -> Now we got a task card.
472.514 -> So what we're gonna do next is
get this project page working.
475.11 -> So when you click on the project,
476.614 -> it actually goes to the project
page where you can see the task.
479.473 -> So, let's do that right now.
481.011 -> It'll just follow four or five, or
whatever that is it'll do that.
485.532 -> So, let's fix that.
493.697 -> So, for the project page, and this is why
I was saying we have to make the task card
497.709 -> flexible, because the project
page is gonna be responsible for
500.895 -> getting its own project
based off the ID of the URL.
503.435 -> And if we're already getting a project, we
might as well just put include task, true.
508.04 -> So, if we're gonna reuse the task card,
510.473 -> the project is all ready
getting its own task.
513.195 -> Why do we need the task
card to get the task again?
515.682 -> And it's not even getting all of them,
it's only getting the first five.
518.307 -> So that's why I extended the task
card to take in task as a prop, so
522.021 -> it could either give it a list of tasks or
it'll go get the first five by default, so
526.683 -> that's why we did that.
528.121 -> So, let's go make this so
we'll go into, they'll quit.
532.815 -> We'll go to dashboard project ID page,
538.409 -> and we'll just make our stuff in here.
543.846 -> So export, default, async.
551.177 -> Function, this will be the project page.
560.003 -> There we go, we'll need to get data,
570.232 -> That's gonna be async, gotta see
if this is the user first, always.
574.644 -> So, we're gonna await get
user from cookie or cookies.
584.53 -> This is gonna take an ID,
it's gonna be a project ID.
588.988 -> Then we can say cons, project
594.194 -> equals await db.project.find
600.027 -> unique or is it find first.
604.824 -> Yeah, it's find first,
it's not a unique index.
607.252 -> Find the first one where
the ID is gonna be ID and
615.021 -> the owner it's gonna be user.id
622.713 -> Or owner ID, sorry, it's user ID.
629.652 -> And then we just wanna
include all of our tasks.
639.214 -> From there,
we're gonna just return the projects.
641.158 -> We'll do structure to If you want to,
you can do whatever.
642.99 -> There's no wrong or right there.
645.536 -> Cool, we got that.
649.087 -> Now because this page is a dynamic page,
652.29 -> as in,
its parent folder has brackets around it.
656.255 -> That's what makes this a dynamic page
will automatically get past perams.
663.931 -> Every page that's a page inside of
a folder like this is gonna get params.
672.126 -> So we can say const project
= await getData, and
677.108 -> we can pass an ID which
will be params dot whatever
682.089 -> your folder name is, in our case, it's ID.
697.179 -> And then from there,
it's really just some basic jsx.
711.152 -> I'm just gonna bring up my
task card There we go task.
723.196 -> Task card, task card.
726.991 -> Yeah, okay, yeah, so
you're gonna get a tight grip type here.
734.225 -> Because it doesn't know how to handle
components that return promises yet
739.203 -> there's a fix for it.
740.713 -> There's a comment you can put in here for
TypeScript to ignore this, but it's fine.
747.104 -> And these are just tripping
because project might be no,
750 -> we're not handling that, we're just
not handling everything which is fine.
754.06 -> Okay, any questions on this?
756.059 -> Let's try it out.
757.558 -> So if we go here, click little refresh.
760.463 -> See our 60 frames per second spinner,
click on one of these projects, boom Boom.
767.09 -> Got a project with all the time.
768.638 -> >> [MUSIC]
Source: https://www.youtube.com/watch?v=Ic40KOMOcO4