Next.js 13 Crash Course | App Directory, React Server Components & More

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's going on guys in this video we're going to be looking at next JS version 13 and we're going to look at all the new features such as the app directory we're going to look at react server components and how to fetch data from server components we're going to look at layouts the new API route handlers so all that stuff now I just want to mention that if you're brand brand new to nexjs and you've never used it you barely know what it is I would highly recommend watching my other next JS crash course first the one that I did about a year year and a half ago that's more introductory and more beginner friendly this is more for people that have at least dabbled with nexjs and want to learn about the new version 13 features all right so this blog post from nextjs.org will tell you about them you know the layouts app directory data fetching and all that what I want to do is build a little project and show you all that stuff along the way so this is what we're going to build it's just a little application where we're showing some courses on the home page and what we're going to do is create what are called route handlers which take place of the the previous API routes and will serve some courses we'll be able to search them as well we'll have an end point for for that as well but that's more towards the end of the tutorial what we're going to start off with is just getting set up we'll talk about layouts routes so the way that you set your routes up is a little different when it comes to naming your files and folders we're going to look at server components and how to fetch data from those we're actually fetching data from the GitHub API here and there's a loader that will just show automatically if you just create a file called loading.js or loading.jsx which is really cool so we don't have to like say if loading or anything like that in server components and then if we click on one of these it'll take us to a single repo with some data from the GitHub API and notice how the directories came in a few seconds later what we're doing here is make making multiple requests and we're using something called a suspense boundary so that you can load in the data that comes in but if something takes a little longer you can just put a placeholder there rather than waiting for everything to load um so it gives you it gives the user a better overall experience okay so that's what we'll be building we'll look at some of the other little features along the way so let's jump into it [Music] okay so we're going to start up our project there's a few ways that you can get into next JS we're going to be using Create next app which is similar to create react app so just navigate in your terminal to wherever you want to create this project and make sure you have node.js installed and we're going to use npx create Dash next Dash app and at this time if you want to use the the new app directory structure you have to do at latest so let's go ahead and run that we should get some questions so project name let's say next underscore 13 underscore crash I guess yeah I guess that'll do and then um if we want to use typescript I'm going to say no to that eslin say no just want to keep this simple we'll say no to having a source directory and then it's going to ask us if we want to use the experimental app directory and for that I'm going to say yes and then your import Alias we'll keep that at the at symbol that's just so you can import things from you know deep in in your directory so you don't have to keep doing dot dot slash dot dot slash all right so now we have that created so I'm going to CD into next 13 crash and then I'm going to open vs code and of course if you're using something else just open your editor and open up this file structure so what we'll do is run the dev server so I'm going to do that from the vs code terminal so npm run Dev and then we'll just take a look at some of the files that were just created so let's go to localhost 3000 and you should just see this landing page here so as far as the files we have our package.json which is really simple we just have react react Dom and next as our main dependencies and for scripts we have our Dev script which we just ran when it's time to build for production we can do npm run build that'll Run next build and then to test that production build you can run npm start and then if you also want to use a linter you can do npm run lint so pretty simple package.json in the config file you can see that we have this experimental object with app Dura set to true and that's because I chose yes for the app you know the new app directory structure so in that app folder is right here and that's where everything we create goes all of our Pages components all of our API route handlers everything goes in that app folder all right now the first thing that I'd like to do is just kind of clean things up a little so page.js is is going to be our home page so you can see this jsx here that's what we're looking at here in in the output on the home page so I'm actually going to just completely get rid of everything in here just to keep this simple and I'm going to create a new component now I'm using the es7 react Redux Snippets extension and with that I can do r a f c e which is react Arrow function component export so it'll just give me a very simple arrow Arrow function component and I'm going to call this home page okay because this is a page component and the convention that I use is always to use page at the end of whatever page it is so let's go ahead and save that and we should just see home page now as far as styling goes we do have our Global CSS but what I want to do is clear everything out of that and then in the the final repository the link is in the description you'll have a global CSS there and I just have a bunch of custom Styles so I'm going to just replace that Global CSS with the the one from the final project and you can see that now we have this this really dark gray background color and I'm importing the the Poppins font and using it here but in a little bit I'm going to show you that with next 13 you can actually import fonts so we won't even have to do this but for now I'm just going to leave it the way it is and just like with past versions of next.js you can use CSS modules and you can you know bring them into your components but we're not going to do that so I'm just going to delete the page module CSS so the first big thing I really want to talk about is routing and in past versions of nexjs we had a Pages folder and in that Pages folder if we created and let's let's say an about.js or about.jsx file we could then go to slash about in our application and it would load that component well routes work a little bit different in next 13 when you're using the app directory so what we want to do and we'll use an about page as an example we'll create a folder not a page but a folder called about and then in that is where we can add different types of files depending on what we want if we just want the page right if we just want the the component then we create a file called page.js or page.jsx which is what I prefer so I'm going to go ahead and do that and then we'll go ahead and just map out a quick component here I'll call it about page and we should be able to go to that route now for the moment but since we don't have our header with any navigation or anything I'm just going to go to the home page and just add a couple links here so let's get rid of that and we'll just put a an H1 here I'm going to say welcome to travesty media and then underneath that I'll just have a UL With An Li and we're going to need to use the link component so we're going to bring that in so import link that's going to be from next slash link and we'll put that in here now another thing that's changed is we don't put a tags in within the link anymore before if we wanted to add a class for example we would put the class on the a tag well now you would put it right on the link all right but we don't need any classes so we're just going to have an href that's going to go to slash and let's just say home copy that down a few times we're going to have about say slash about and then I'm also going to show you how to have nested routes so we'll also have one that goes to about Slash team all right so if we save that we should see this on the home page and if I click on about we go to slash about and it shows that that page component okay and home obviously goes to the the home page now as far as nested routes go actually on the about page I'm just going to add real quick we'll just say an H1 and say about travesty media and then I'm just going to put some dummy text in here yeah we'll just do that okay so the next thing I want to show you is a nested route so if I want about Slash team I don't put a file named Team JS in the about folder we have to create a new folder remember every custom route that you create is going to be a folder name not a file and then inside team we create a page.js or jsx and then let's say we'll call this call it team page and I'm just going to put an H1 here and we'll say our team and then we'll just do a paragraph with a little bit of dummy text okay if I save that now I should be able to go to the team page or team route okay about Slash team and I could Nest even further if I put something in team like a folder called Brad then I could go about Slash team slash Brad so that's that's how the routing is going to work when you're using the app directory so the next thing I want to look at are layouts so in the past with older versions of nexjs you'd usually create a layout because you had an underscore app.js which was like your main app component and then you'd create your own layout component to wrap everything well with next 13 and using the app directory we have a layout.js that wraps everything so basically it's just a component called root layout and it gets children passed in which is basically everything any other page any routes we create and this is also where the HTML and body tags are so anything that you're going to want on every page such as a header you're going to bring it into here and then embed it into this layout component now like I said this is the the main layout component and if you want to have separate layouts you could go to for instance about and then create a file called either layout.js or layout jsx which is what I prefer in fact I'm going to just I'm going to rename these as well so this will change that to layout jsx and then the home page also jsx which is just preference you don't have to do that but that'll still work just fine all right now in this uh in this about layout we'll go ahead and create a component and call it about layout and then this just like the root layout it's going to take in props and it's going to take in children and then wherever we want to put that in the layout we just output children and just to show you that we're using the layout I'm going to have an H1 and just say this is the about layout all right so any pages that use this layout we should see this H1 so if I save that of course the home page we're not seeing the H1 but if I go to about we are seeing it all right and even if I go to about Slash team we're still going to see it because the layout here is going to trickle down into any child routes or child folders however if we wanted team to have its own layout we could also put a layout JS inside of the team folder okay so that's how that works now I'm not going to keep that layout I'm going to delete it I just wanted to show you that you can have custom layouts you know you might have a login and register page where you just want the Box you don't want any navigation or anything like that that's a good example of where you might use a custom layout now in the layout file we have this metadata object so this is going to be your page title your description your keywords any meta tags that you want and this is your basically your Global meta tags so I'm going to just change this to Traverse media and then for the description we'll just say web development tutorials and courses and then if you wanted keywords we could also do that I don't need this many I'll just just go with this yeah all right now if I save that and we come over here you'll see that travesty media is going to be the page title if I reload that it's going to be the page title for all of these right now you're probably going to want to have custom page titles at the very least for your other Pages especially if you're building websites for like small businesses where SEO is really important so that they can be found so what we could do is go into our about page now you could have a custom layout like I just showed you and put the metadata there but you can also put it right in the page so you just want to make sure that you export this metadata metadata object so let's say title and for that we'll just say about travesty media and if you want to have descriptions and keywords of course you can do that as well and now if we go to about we should see that about travesty media okay it's not going to show on the team it's only going to be for that specific route it doesn't trickle down into other routes unless it's a layout okay so that's the metadata API now before we start creating other components and and working on our project I want to show you that we can also import fonts we can import Google fonts and some other types as well but right now in my Global CSS I'm importing it through the CSS the pop-ins font so I'm going to get rid of that that import and also get rid of the font family specifying pop-ins and now if I do that you'll see we go back to the default font for the browser so what we can do is in the layout or really in any file but since I want this font to apply to everything I'm going to bring it into the layout so let's go at the top here and let's say import and we want to bring in in in curly braces whatever Google font you want I'm going to use Poppins and that's going to be from next slash font and then slash Google okay and then the next thing we want to do is create an object let's say const Poppins lowercase and we're going to set that equal to Poppins uppercase what we just brought in and that will take in an object of options such as the weight now the weight can be a string like if you just want say 400 or it can be an array of strings if you want multiple weights which I do I want 400 and then for bold I want 700. okay and then you can also add subsets so for subsets we'll say Latin now to apply this we can use this object this variable so Poppins and then dot class name that will give us a class that will apply the font and I'm going to apply it to the body because I want it to I want it for everything so let's say class name we're going to set it to some curly braces and say Poppins dot class name so now if I save that we come back here now we have the Poppins font and we didn't have to bring it in through our CSS all right let's see I also want to just wrap the children right here I'm going to wrap that in main tag and I want to give that a class name of container which is just a class I have in that CSS file all right so bring that into there and that'll just add some padding and stuff and adds a little container around it now if you open your your console you might see some weird errors and a lot of times it's because you have extensions installed for instance I have LastPass installed and let's see it's not doing it right now because I oh it is doing it yeah so if you see something like this extra attributes from server it basically means that the server output or the server mockup doesn't match the client and a lot of times it's because you have browser extensions that add extra um you know extra HTML or extra markup to your page and it doesn't match so you might see issues like this just try disabling some extensions if you do all right or just you know just ignore it but there's nothing wrong we didn't do anything wrong in this project we barely did anything and I'm still seeing it and I think I have LastPass disabled I'm not going to go in and get into it but it could be another one you can see I have quite a few Chrome extensions all right now the next thing we'll do is create a header so I'm going to go into app and any components that aren't Pages I'm going to put into a components components folder so in here let's create a file called header.jsx all right and then I'm just going to use header tags as the the wrapper element here and we're going to have links in here so we also want to import link okay and then let's um let's see I'm also going to give this this header a class name of header and the Styles should just apply because of that that CSS file then we're going to have a container I might disable co-pilot if it gets too annoying so we have our container and then in there we're going to have our logo class and let's have a link that'll go to the home and we'll just say Traverse media if I could spell my own name all right and then let's see under the logo let's have a class of links and that's where we'll put our navigation so we're going to have a link to about and let's say our team and that will be about Slash team and then we're also going to have a link to let's say code and that's going to go to code slash repos which doesn't exist yet but I'm just putting it in there now I want this header to obviously show on every page so I'm going to bring it into the layout not into the home page so let's go ahead and bring in import header and we'll put this right above the main tag here so we'll save and there we go so now we have our header we can navigate code isn't going to work right now but what I want to talk about real quick are react server components versus client components and this header that we just created along with our other page components are all react server components by default when you create a component it's going to be rendered on the server unless you specify that you want it to be a client component and there's differences so I want to go over that right now so I'm going I don't have any slides or anything so I'm just going to paste it in this file and this is from the blog post so basically I have a blog post that is a written version of this crash course if you want to check that out I'll have the link in the description but some advantages to react server components are that they load faster because you don't have to wait for the JavaScript to load in the end you end up with a smaller client bundle size because a bunch of components aren't included in the client SEO friendly obviously that's a huge one that's a huge reason to use next.js in general access to resources that the client can't access so certain packages that you normally wouldn't use on the client like like orms to deal with databases and stuff like that hide sensitive data from the client so API keys and stuff like that more secure against cross-site scripting attacks and in many cases it gives you an improved developer experience because they're simple a server component is much simpler however there are limitations or disadvantages which are they're not as interactive so if you have components where you're going to have a bunch of state and you know you have use effects and you have a bunch of things going on then you can't use a server component with a server component you can't have components State you can't use the use State hook okay in fact I'll show you in a second that if you even try importing it you're going to get an error you also have no life cycle right it's just loaded when the page loads so you don't you don't you can't use the use effect hook all right so there's definitely limitations depending on how interactive you want your components to be now just to show you real quick if I were to in this header import use state and I save I'm going to get this error it says you're importing a component that needs use state it only works in a client component okay now to make this a client component if I wanted to use the use State hook all you have to do is go to the top here and in quotes just simply say use client and now you see that error goes away and I could treat it like a normal uh you know normal client-side react component and I could add State I could bring and use effect and all that stuff now since I'm not doing that I'm going to keep this as a server component which is normally what you would do in this situation now the next thing I want to get into is fetching data from a server component which is actually really simple with a client component you would usually bring in use effect you have your use effect dependencies which can kind of get messy and can kind of be a pain fetching data with a server side component is very simple so in the let's see we're going to have this this code this goes to code slash repos I want to create a route for that so in app we'll create a folder called code and then in there we'll create another folder called repos and then in there we'll create a page.jsx okay and then we'll say rafce let's call this repos page okay and if I save that and I reload we should see this repos page so what I want to do from here is fetch my GitHub repos now with the GitHub API I'm sure a lot of you have used this but if we say if we go to API dot github.com users slash and then whatever your GitHub username is and then slash repos that's going to fetch an array of your code repositories so that's the end point that I want to hit now to fetch data we actually just use the fetch API in fact it's kind of a superset of the fetch API there's some things added to it so first off let's um see how do I want to do this we'll just fetch the data first and then we'll work on you know displaying it in the UI so I'm going to create a function an async function because I'm going to be using a synca weight so we'll call this get repos or let's call it fetch Factory bows and then what we're going to do is just simply use the fetch API in fact I'll use this copilot snippet so we're setting a response variable and we're waiting on this fetch to this URL and I just want to change the user to my own so let's say Brad traversy and of course you can put your own GitHub username and then we're just returning the Json in fact let's say const repos I just prefer to to do that I think it's a little more clear so we're returning repos so this will return a promise so down here in our component what we'll do is let's make this asynchronous so async and then above the return we're just going to create a variable called repos and we're going to await on that fetch repos function all right now before I I do any output or anything let's just console log to make sure that we got them so we'll say repos and I'll even put in the jsx we'll just do like the the name of the first one so we'll say repos because it's an array so we'll say zero and then we'll get the let's say name I think it's either name or title pretty sure its name so we'll do that and let's save and go back to our repos page and you'll see 50 projects in 50 days all right so we know that we're fetching it in fact if we look at the console down here you can see it now just remember this is a server component so if you do a console log from it you're not going to be looking in the client right you're going to look down here so just keep that in mind as well if you if you say use client at the top and then you console log then it's going to be in the browser so let's get rid of that and then we're going to start to create our output now if you want to just copy the code from the repo and skip the the output part you can do that but I'm just going to go through this and create it I'm going to actually open up a new terminal because I want to install react icons which will allow me to use Font awesome icons okay so now we'll come back over here I'm going to import a few things we want the link because we are going to link to an enter page and then let's also import from react Dash icon slash fa and I'm just going to bring in a couple icons so I want F A Star for the Stargazer account and then we'll do f a code branch and also f a i all right now down here in the output let's see we'll get rid of this and we're going to have this this wrapper div let's give it a class name of repos Dash container which is just a class that I have in the in the CSS and then let's have an H2 we'll say repositories and then we're going to have a ul and let's give it a class of repo Dash list and then we're going to map through the repos so let's say repos dot map and we'll say for each for each repo then we want some parentheses and for each one we're going to have a list item we don't need this class name uh yeah so we'll have a key let's close that off so the key is just going to be the repo ID and then we do want to have a link wrapping around the entire thing except I don't want it to go to the actual GitHub page that's what this would do right here I actually wanted to go to an enter page so it's going to be let's put some back ticks and say slash code slash repos slash and then whatever the repo name is all right and then let's see inside the link we're going to have an H3 and let's do repo dot name then we want the description we'll put that in a paragraph So repo Dot description and then we want the details so this will be a div let's give it a class of repo Dash details okay and then in here we're going to have a couple spans and in the span will be the icon let's say f a star and that will be the stargazers count then we'll have another span and that's going to be the forks and then we'll have one more and that's going to be the Watchers and that should do it so let's save and there we go so now we're fetching all the repositories from my account and we're displaying them with the title description and then the the stats if I click on it it's going to take us to code slash repos slash and then the project name so this is a dynamic route and I'm going to show you how to how to do that in a minute but yeah so this is a a react server component you can see how simple it is to fetch data we're not using any use effects with dependencies with any weird stuff happening it just simply fetches the data puts it on the page now the other thing I want to show you is the the loading page that we can create so when it's fetching the data we can display a spinner or if we just want it to say loading repos or whatever we can do that very easily all we have to do is in the app directory is create a page or a component called loading dot jsx or JS or Tia or TSX whatever it is you're using now you can see here it's going to give us an error because it is actually looking uh it's looking for that component and it's not there so let's go ahead and create this we'll say rafce and then as far as the the output I'm just going to have a div with the class of loader because I just have this in my CSS created a simple spinner and then a div with the class of spinner all right and let's call this actually say loading page you can call the component whatever you want you just want to make sure the name of the file is loading JS or jsx all right so now let's do that okay so it's really quick so what I'm going to do is in um in the the repos page here in the fetch repos I'm gonna just make it take one second before it loads the data so after the response let's do this we'll say a weight new promise and we'll pass in here let's say resolve and then we're going to have a set timeout until it resolves after one second so let's put um I'm missing a parentheses here yeah we'll just say wait one second all right so now let's save that and if I reload now you can see for one second it shows that spinner and that's just from creating this this loading jsx so I didn't have to put in you know bring in use State and say is loading set it to True fetch set it back to false enough to do any of that so if it's a server component and you're fetching data and you have that loading page it's going to display which I think is really cool now we're going to talk about Dynamic routes because we want to be able to click on one of these and have it go to to that specific repo page so what we would do since I wanted to be slash code slash repos slash and then the name where the name is dynamic I'm going to go into repos and create a folder with brackets and then whatever that name is so in this case it's it's the repo name but in many cases it's going to be ID or you might have you know title maybe if it's a Blog something like that now in this name folder we're going to create another page.jsx so you can see that the the the actual page for the route is always named page jsx you're not going to call it anything like about or code or repos or anything like that now here let's do to rafce and I'm going to call this repo page so singular and let's say for now let's just save that and we should be able to click on one of these and it takes us to that repo page component so to get the name because obviously if we want to get the data right we want to fetch the repo we need this name out of the URL so to do that we just pass in a prop of params okay so params and then I'm going to destructure this further I could just do let's say let's actually give this div a class name of card and then we'll have an H2 and I could I could do this params dot name let's try that and there we go that works however I don't want to have params here so I'm going to destructure this further by just saying colon and then I'm going to pull out name and then I can just do name like that and that still works all right and then under the H2 I'll have a paragraph and just say repo details now I want to introduce suspense boundaries to you where it allows us to have certain loaders or placeholders for certain components that fetch data because we're going to be fetching two things here we want to fetch the the regular details and then I also want to get the contents or the the directories in that repository and I'm going to have them load at different times and I'll show you how to use a suspense boundary so before we do that let's create the components that are going to load the details or the regular data and the directories so in components we're going to have two new files one called repo.jsx that'll be just like the basic data you know the name the stargazers and all that and then we'll also have repo dirs.jsx which will be the list of directories so we'll start off with just the the repo jsx and let's go ahead and actually we'll create a component first rafce and we'll keep it just called repo that's fine and then we want to fetch the individual repo and we're we're going to need the name for that so when we embed that in our page jsx we'll embed it and we'll pass the name in which comes from the URL right so this will take in some props and we'll have a name and we'll have a function where we can say const repo set that to a weight and then fetch repo singular and then pass the name into that right and this has to be asynchronous this function and that's how we'll fetch it now we need to create obviously we need to create that function so let's say async function and fetch repo so the end point is actually going to be API github.com repos slash and then it has to be the username so after repos you're going to put your username or mine whatever you want to use and then slash and then the the name okay then we'll get the Json and we'll return that now I just want to test this out and make sure this works so we'll do a console log here of repo and then what we'll do is bring it into our page so this is our repo page we're going to import the repo component and it's using the Alias here just because it's you know it's a bunch of levels deep and then let's go see how we want to do this we'll get rid of this H2 in paragraph and then we're just going to embed repo we're going to pass the name in which comes from the URL okay we'll save that and now in the console down here you can see that it's giving me that specific Repository so at least we know that this is fetching so now we just need the output for this component now I'm going to bring in a couple things I'm going to import link because I do want to have a link to the actual GitHub page and then we're going to need some icons so say from react icons and that's going to be slash fa let's say f a star f a code branch and f a i okay and then down here in our output let's get rid of that console log and this can just be a fragment and then we'll have an H2 with the name and a paragraph with the description then we're going to have a class of card Dash stats and in there we'll have a class of card Dash stat and that's going to have the f a uh yeah f a star and then we'll have a span with the stargazers count and then this div I'm just going to copy that down twice this one is going to be f a code branch and that's going to be for Forks so Forks count and then this one we'll say Fai that's going to be the Watchers count so let's say Watchers count we save that and there we go so we have just our basic repo data now I want to get the directories as well actually let's put a go back link here so in the page jsx I'm just going to bring in link and inside the card here we'll just say link actually I wanted to go to slash code slash repos and we'll just say back to back to repositories and close that off okay actually I'm going to give this link a couple classes that I have so let's say class name let's do BTN and BTN Dash back okay so now we can go back and go to this one all right cool now I want to have the the directories so we actually want to make another request from the repos durs component that we created so let's do that now so rafce and yeah we'll call it repos durs and then let's let's see this is going to take in the name as well so we're going to destruction our name and let's see above the return here we're going to have let's say const and we're going to call this contents because the contents of the repo and then we'll have a function called fetch repo contents and pass in the name and of course this needs to be asynchronous okay and then we'll come up here and let's create that function so we'll say async function effect repo contents and let's see is that correct yeah so it's going to be repos slash and then your your username slash whatever the repo name and then slash contents and then here we're just getting the Json and we're returning it now I want to make this take longer because that's that's going to let me show you what the the suspense boundary does and we create that so let's go up here and we'll say a weight new promise and we're going to set this to let's say three thousand so three seconds okay so it's just going to take three seconds before it gives us our data and then let's see for the output from this contents we want to get the directories because this will give us everything it gives us the files and all that so I'm going to go like this considers and then we're going to just filter through let's say contents filter through and here we're going to check the type and just make sure that it's dur make sure it's a directory now down here in the return let's just go ahead and add an H3 and we'll say directories that down there all right so we get our directories we'll have a UL and then we're going to map through our dirs so durs.map and let's say for each directory then we want to return a list item so we'll say list item give that a key and the key we're going to set that to the path so say der dot path and then in the list item we're going to have a link to the actual directory on GitHub uh let's see durapath I think I want to change that to path as well okay so I think that'll do it let's save that and then we're going to go back into page jsx and we're going to bring in say import repo durs and then just like we did here we're going to pass the name in say does let's save that all right so right now what's going to happen is we get an error and link is not defined so in repo durs we just need to import link all right so you'll see we get the spinner and it's going to give us the spinner for three seconds because what's happening is it's going to be in that loading State until everything is fetched even though the the repo here is fetched right away right it we get it quickly since the duras takes three seconds we still have to wait and just look at that spinner so what a suspense boundary lets us do is load everything that that can be loaded such as you know this data here and then we can have a specific placeholder for the directories component because that's what's taking so long okay so it's pretty easy to add this all we're going to do is go into the page where we have the two components right we have our repo which comes back right away we have this repo durs which takes you know three seconds so we're gonna import up here say import suspense capital S suspense from react and then we're just going to wrap these components and these this is called a suspense boundary so we'll say suspense and we're going to add a fallback now the fallback is going to be whatever component you want to load if you want to have a spinner or something like that you can but I'm just going to say loading repo and then we just want to close that off here okay and then we want to do the same thing for the directories so here I'm going to paste that in except I'm going to say loading directories and let's close that off so now if I save that and I come over here and reload we don't get a spinner for three seconds everything loads except the directories and we just see loading directories so much much better user experience because you you never know how long something is going to take to fetch I mean this stuff comes pretty quickly I have a quick connection and all that but it could take a few seconds and you don't want to hold up the whole page because of that one request so that's where suspense boundaries come in now I just want to talk about caching and revalidating real quick and I actually wish that I mentioned this earlier when we first started talking about fetching data so by default in your production build fetch will cache everything indefinitely and this is great for performance but it can cause issues if what you're fetching changes often and in the past in in previous versions of next.js we had get static props and get server-side props where get static props would be for more like a static website where data isn't really changing and then get server-side props would you know fetch at every single request and that's good for data that's often changing now we don't have those different methods here we use fetch no matter what but there is an option called revalidate and what that does is it tells nexjs how often to check for new data so we're going to put this in all of our fetches so I'm going to go to repos page.jsx where we fetch our initial list of repos and what we would do is just after the endpoint inside fetch is we would add an object and then in that object I'm going to add next which is another object and in there we can say re-validate okay and then that's going to be the number of seconds that we want to wait until it it fetches fresh data and we're going to say 60 seconds okay so basically it'll cache it for 60 seconds and you can change that to whatever you want all right but if you if you're working with data that's often changing then you're going to want to do this for something like this this project where we're fetching my repositories I mean how often is that really update how often are you adding new repositories if it's not very often you might want to just not even put this in and just have it as a static website all right because at that point it just fetches it once and that's that but again if you have data that's often changing then you want to add this so I'm just going to copy this object and then we're also fetching in these two components repo and repo durs so I would just add that here as well let's see let's paste that in like that and then in repo does paste that in there and everything should still you know work fine and if you were to build this out now and if you were to add a new repository it would pick that up you know after 60 seconds if you don't add this then it's not going to pick it up so just keep that in mind and you can read more about this in in the documentation okay now the last thing that I want to talk about which is going to kind of take a while is API route handlers which allow you to create custom request handlers for a given route so instead of having like a back end Express API in many cases you can just keep it within your your folder structure here so I'm just going to close everything up and this is where this API folder comes into play now you can actually have route handlers within your page routes so it doesn't have to be within this API folder but if you put it in here then it's going to be prefixed which with Slash API now it has this hello as a you know as an example so I'm actually going to open up Postman you can do this with your browser because we're just making get requests right now but I'll just show you within uh let's see I'm just gonna go here all right so I want to make a request to http localhost Port 3000 slash API slash hello and you'll see I get hello nextjs 200 response and the way that we structure this is similar to with our Pages the name of the route is going to be the folder and then the actual code goes in a route JS file now as far as how we structure it it's a bit different than what we did with uh with past versions with past versions We would have a function named Handler right but here we actually call the function whatever whatever method we want in this case get right if I change this to post and then I try to make this get request I get 405 method not allowed because there is no get for that row right so if I change that to post and I make that then I get hello nextjs okay so you just want to call this whatever um you know whatever method you're using now what I'd like to do is just fetch some some course data and I'm I'm just going to use a Json file although since your route handlers our server side you could use some kind of orm you could use like Prisma or something like that if you want to fetch data from a database but what we're going to do is in API create a folder called courses and inside courses I'm going to have a file called Data dot Json and then I'm going to paste some courses in there and you can get this from the repository in the description if you don't want to type it out but we just have some courses with an ID a title a description a link and a level okay I think we have five yeah we have five of them so I'm going to save that data file and then in courses I want to have a route so let's create a route dot JS file and we would I just want to have a route that returns those courses so first of all we want to import the courses from that Json file so we'll say import courses from and then dot slash data dot Json okay and then I want to send a response from this so I'm actually going to import next response so next response from next slash server and then let's export function we're going to say export async function and call it get because it's going to be a get request and then I'm just going to Simply return next response now if I do just next response like this it'll actually return just a string I believe or just text but if you want Json then you just add dot Json and then courses is just coming from the Json file so if I save that and now I make a get request to API slash courses there we go I get a 200 status and I get the data so what I'd like to do now is show those show this on the home page right so let's go back into our I guess you would say our front end and let's see I'm going to have a separate component for this so let's see in components let's create a full a file called courses Dot jsx so this is where I want to fetch the data from and I'm going to create a component we'll keep it yeah we'll call it courses and I'm just going to import link because I'm going to have a link to the the course page because that's in the data right here the link which I'd highly recommend you check some of them out if you want and then let's see we want to fetch so this is going to be a server component so let's say async function fetch courses and let's see what it gives us no I don't want that so let's say const response and we want to set that to a weight fetch and yes that's what I want to fetch is localhost 3000 slash API slash courses and then let's do cons courses equals the Json and then return courses all right and then inside the component here in the function we're going to fetch our courses we do need to make this async and then we want to await on the fetch courses and then what we'll do is just map through those I'm going to give this div a class name of courses and in here let's take our courses and let's do map and we'll save for each course we want to return in parentheses let's see we're going to have a for each one we'll have a div yeah let's do a div with the course ID for the key and I'm also going to give this a class say class name of card and we'll close that div and then inside the div here let's do the course title although I'm going to make this an H2 and then I'll have a small tag and let's say level colon and put the course dot level and then a paragraph with the course Dot description and let's see we'll have a link so link href is going to be to um no we don't want it to go to that we want it to go to the link that's in the data so that would be course dot link s all right and then inside the link we'll just say go to course and let's also make that open in a new tab so we'll say Target equals underscore blank and let's also give this class name of BTN all right so that should do it now I want to bring this into the home page so let's go to our root page jsx which right now just still has these links so we're going to get rid of the UL that can just be a fragment and then let's import the course component and then we'll add that here so courses okay let's save let's check it out go to the home page and there we go so now we've created a route Handler which is essentially just an API route in next.js with courses that are coming from a Json file but you could just as well have them come from a database and we're displaying them on the page now I'm also going to show you how to get query params so for instance if we want to search courses and maybe we want to have a route that's like slash search and then we want to have a query so we can say like question mark query equals react so something like that so I want to show you how to get how to get this value so let's go back into our course routes actually we're going to create another route at slash slash courses slash search so in the courses folder that's in API let's create another folder called search because it works just like the pages so this will be courses slash search and then I'll create a file called route.js in search and then this is where I want to have you know have that that endpoint or that route Handler so let's import say next response and I'm also going to import the courses and that's going to be one level up so dot dot slash data Json and then we'll say export async function get request and we want to be able to get this this value that's in query and and this could be called anything you call it queue or whatever you want to call it but I called it query so the way we can get that is by saying const and we're going to destructure search params from whoops from new URL and we want to pass into here not this so we want to pass into here just request and then dot URL okay so this will have any query params that we pass in fact what I'm going to do right now is just do a console log of request dot URL just so you can see what that gives us so if I make this request right here I'm going to get all the courses because that's what I'm returning but if we look in the console you'll see the request URL is this right here however you can extract the search params so let's console Log search params if I make that request again you'll see we have URL search params query and react and if I add some other stuff on here look if I do ampersam and then name equals Brad and I run that you'll see that now name and Brad is on there now to get a specific value like to get react or name we have to do search params.get and then pass in query or name or whatever it is we want so if I do search params.get oops Yeah dot get I can't see and then we pass in here a string of query and then I make that request again now I get react if I want to get the name and make that again now I get Brad all right so what we want to do is basically filter our courses to that query so I'm going to put that back to query and instead of console logging this I'm going to say const query and set that to whatever query is passed in all right now before we make our response let's filter the course so we'll say const filtered courses and we're going to go ahead that's yeah that should do it I love GitHub copilot and you can see why like I didn't have to type this crap out I'm not a very fast typer as you guys can see especially when I'm talking so it's really nice to for this to just you know pop in there so we're filtering through the courses right so this will basically Loop through and then we're returning the course title as lowercase if it includes the query which is also too lowercase that way even if you were to type in react with all uppercase it's still going to match okay and then we just want to return instead of courses we want to return the filtered courses so now we can take the name off that was just to show you but if we do that now we just get the react course if I do let's say JavaScript I get the JavaScript course now I want to show you how we can get body data right I mean I just showed you how to get query params from the URL but what about if you have a post form let's say to add a new course you need to get that data from the body so you need to know that as well so what I'll do is go to API slash courses slash route JS where we have our just our regular get request to to get all the courses I'm just going to close this stuff up here um and I want to have a post request so let's say export async function post and pass in our request all right so With a Little Help from uh from GitHub co-pilot here basically to get the body data we use request dot Json so I'm gonna actually [Music] um you know what for now because I just want to console log some stuff so I'll just return let's say a message course created and I want to extract let's say const we're going to destructure here from request.json and I'm just going to get let's say title description level and Link yeah so just get that for now and then I'm going to console log title description level and Link so let's save that and let's go over I'll just open up a new tab and we're going to make a post request now to API courses and in the body I'm going to go to Raw and let's add a title so title we'll just say my course let's do a what else description say this is my course let's do link https something.com and then finally we have the what's the other one level will say beginner okay so I'm going to make this request with that body and if you look in the console we have my course which is the title this is my course description beginners the level and then the link so that's how you can get the Json data from the body now let's say I wanted to create a new course and again obviously we're not using a database but we could at least add it to to memory so we would want an ID so what I'm going to do is go into my other terminal here and say npm install and I'm going to install uuid which will allow me to create a uuid a random one and then we're going to import that so we'll say import and the way we import this is I think copilot just had it yeah that right there so V4 as uuid V4 and then what we'll do is down here let's say const new course equals we want the ID set to uuidv4 that'll just give us a random ID the title the description and the level and the link so that's our new course object and then what we'll do is take courses and we'll push onto that the new course and then we'll just return let's say response.json and we'll return courses which should include the new one and again it's not persisting anywhere it's just from memory but let's go ahead and try that so we have our posts we have our data let's run that and now we get back a 200 response with our courses and if you look at the bottom one here that's our new course it has the uuid title description level and Link all right now I'm not going to actually have a UI to add a new course I just wanted to show you how we can get data from the body but I do want to actually create a search component so let's use that search route in our front end and this is going to be a little different because since we're now going to fetch data through the search box we're going to keep refetching it so we actually need to change it up from from using a server component to using a client component and the main reason I wanted to do this is so you can kind of see the difference in where you would use a server component versus a client component now we're still going to use the courses component right here but we're not going to do our fetching from here we're just going to use it to to display the course we're going to do our fetching from the home page so if we go to page jsx here we're going to do it from here and we want to make this a client component because we're going to be using State we're also going to be using use effect because remember we're going to have our search component and that's going to be you know constantly fetching data for whatever we want to search for so so let's turn this into a client component by just putting use client at the top now right away this is going to break right here because since this is now a client component and we're embedding a server component that's fetching data it's not going to this isn't going to work so it does take some getting used to to kind of see the the rules of this and and how you know you can and can't do certain things with server versus clients so I think that that's probably the biggest uh you know like the biggest struggle that I've had so far with this but once you figure it out it's it's not that difficult but what we're going to do is just get rid of courses for now since we're still fetching data in that component and then this should work fine now I want to fetch the courses from here but since it's a client component we can't do you know fetch up here like we were with with the server components so we're going to be using use effect and doing things the old school react way I shouldn't say the old school because this is just it's a client component if you want a lot of interactivity and you want search boxes and stuff like that then you're going to be using client components so let's import let's say use state and use effect now the loading page right let me close that API just make this a little cleaner so the the loading jsx page is for Server components when you're fetching data it'll it just automatically works as we saw since I'm going to be fetching data from the client that's not going to just automatically work however I can bring it in and just you know load it manually so I'm also going to bring that in let's go here and say import loading or loading page yeah from loading and let's see I'm gonna think of how I want to start this let's just add our state so const we're going to have state for our courses because that's going to change depending on if we're just loading the page and getting all courses or if we're making a search and getting filtered courses and then we also want loading because again this is that loading page is only working automatically for Server components now I'm going to have a use effect so in my use effect and we'll just have our dependencies and we're not we don't need actually need any dependencies but we're just going to have an empty array and then let's say const fetch courses and set that to an async function and then uh yeah I guess we can just use that so I'm making a request to API slash courses and then getting the data the Json data and then setting the state okay and if you guys know react then you know what I'm doing here and then I'm just setting loading to false which is actually set to True by default all right now we have to call this fetch courses so directly under it we'll say fetch courses and then above the return let's just check and see if loading is true so we'll say if loading then we're gonna return the loading page all right so let's save that and it's not going to show any courses yet it's just putting it in the state we don't have any output but you can see the loader as it's fetching them so now what we'll do is the courses component let's go into there and again we don't need to fetch the data from here anymore so we can get rid of that and then let's see we're not going to need this all we're going to do is get a prop passed in of courses like that and we'll display them the same way so that that can all stay the same then in our home page we'll go ahead and bring in well we're already bringing it in but we'll embed it so let's go down here and right under the welcome put in courses and we just want to pass in the courses from our state which gets filled when we make the request see what's going on here found object promise um this doesn't need to be a synchronous there we go okay so now we're getting our courses but now this this is happening on the client so now what we want to do is create our search component so we can close up that courses component and let's create let's say course search Dot jsx okay and this is going to be a client component we're going to be using use state so let's add use client and we're going to import we don't need to use effects just use state okay and then this is just going to be a form so let's start off we'll just create the the the output first so let's have this return a form and I'm going to give it a class name of search Dash form and it's also going to have submit Handler so let's say on submit and we're going to set that to a function called handle submit and then within the form we're going to have an input and a button so let's say input I'm going to give it a class of search Dash input and let's see the type will be text we'll add a placeholder so say placeholder search courses and the value is going to be query which is going to be part of our state which I'll create in a second and then we want it on change and we're going to set that to function and that's going to take in the event object and we're going to say set query so we want to set that part of our state to whatever is typed in so e dot Target dot value okay now let's create our state here so we have query and set query the default is going to be just an empty string and then under the input we're going to have our button let's give it a class of search dash button and let's give it a type of submit and for the text we'll just say search all right now we want to create our our Handler so let's say const handle submit we want to prevent the default and yeah for now we'll just console log the query let's just get this embedded so we'll go back into our page and let's see we'll bring in course search and we'll put that right here let's put it above courses so course search and there we go so we have our form if I type something in now this is a client component so that's going to be in this console all right so at least we have that displayed and working now we'll go into our search and instead of console logging query we're going to create say response and we'll set that to a weight fetch and put in some back ticks and this is going to be slash API slash courses slash search and then we have our query uh what am I missing here query oh this needs to be async there we go all right so we have our response now we want our data our Json so let's say cons courses set that to a weight res dot Json and then what we're going to do is have a function called get search results and pass courses in because again we need to pass it up into our page all right if you were using like Redux or a context API then obviously you'd set this up differently but we don't need that this is a very small application so this gets search results we just need to pass in here as a prop so let's say get search results all right and now if we go back into our page we can then on the course search let's say get search results it keeps getting in the way now we could put a separate you know a separate function in here called get search results and add that somewhere up here or we can just simply add a function in here and that's going to take in the results from where we call it so right here we're passing in courses which is going to be our results and then we can just say set courses to those results all right so now if we come over here and I search for react search we get react search for JavaScript okay if I search for nothing it should just you know show us all of the courses all right cool and these should go to the actual course pages so that's pretty much it guys loading directories so that's our suspense boundary all right so my main goal for this is just to introduce you to some of these these new features uh using the app directory in next 13. so hopefully you enjoyed it hopefully you learned something uh again you know check the docs there are some uh there are some other little features that I didn't go over but we went over most of them all the big ones um so that's it thanks for watching guys and I'll see you next time
Info
Channel: Traversy Media
Views: 154,896
Rating: undefined out of 5
Keywords: Next.js, NextJS, next js, nextjs 13, next.js 13, next js app directory, react server components, rsc, react
Id: Y6KDk5iyrYE
Channel Id: undefined
Length: 82min 45sec (4965 seconds)
Published: Wed Apr 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.