تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Creating a Next App1:16

Maybe we'll go deeper in the future and do a dedicated series. So let's jump right in. Let's go to Getting Started. Make sure you have a somewhat recent version of Node, and then after that, we can make use of npx to create a Next app. So we can run this command. Let's paste it in here. Let's name it lcNextExample. Okay, that's done. Let's go into that folder, so lcNextExample.

Okay, that's done. Let's go into that folder, so lcNextExample. Let's open it up in VS Code. And we can run the app with npm run dev. Let's open this up in our browser. There's the default page. Let's take a look at the default file structure here. We have our default component within the Pages folder, named _app.js. And we have the default index page right here. We're importing Head and Image from Next, and we're also making use of module.css here,

File-Based Routing Setup2:34

Let's start off with the file-based routing. So as you make pages, Next will create corresponding routes. So let's go ahead and make a About page, about.jsx. Let's make a React functional component. And this is fine for now. Let's make one more for Contact. Contact.jsx. Let's make another one, rfc. And that should be fine. So if I save that, Next should have generated automatic routes for these pages.

And that should be fine. So if I save that, Next should have generated automatic routes for these pages. So if I go to that route, so we have About and Contact. That should work automatically, and it does, cool. You can also specify a folder and put an index.js in there, if you prefer doing it that way. So for example, if we added a new file named Posts, or in the folder named Posts, index.jsx, that would work as well. And let's make a component here. Let's name it Posts here. And let's say, List of Posts goes here.

Let's name it Posts here. And let's say, List of Posts goes here. And this should work the same way. So if we go to Posts, that should work. Now if you need a dynamic route, say we wanted to go to a specific post, say post/1, or this slug, we can create a new file here, put it within square brackets. So in this case, I'll name it id.jsx. Again, let's make another functional component. Let's name it Post. And we can say, this is Post.

Let's name it Post. And we can say, this is Post. And we'll put the id in here. So we have to make use of the useRouter hook to grab that id from the URL. So we can say const router = useRouter(), and we press tab here to import it. Hopefully that imported, there it is. And we can say, this is Post, and let's put the id in here. So router.query.id. Save that. And let's see if that works.

Scoped Styling with Styled JSX4:36

Save that. And let's see if that works. Let's go to post/1 here. And it does work. Cool. Let me also show you another way you can write your CSS that is scoped to your components. So it's built right into Next. It's called styled.jsx. So if you take a look at the docs here, you can write a style tag with a JSX attribute and define your styles in here.

So if you take a look at the docs here, you can write a style tag with a JSX attribute and define your styles in here. So if you do it this way, the CSS will be scoped to this specific component. So let's try this out. You can put it anywhere within here. So let's just put it within the div here. Actually, let me add prettier here. So it formats our code. Let me just add a .prettierrc file. Let me just add some defaults here.

Let me just add a prettier .rc file. Let me just add some defaults here. And now prettier should work. I'm going to paste in that styled.jsx. Let's just say div. So I'll just keep this div here. Erase everything else. And that should be fine. And since this is within a div, this style should take effect, but only on this component. So I'm going to save this.

And since this is within a div, this style should take effect, but only on this component. So I'm going to save this. And I believe I'm missing a closing bracket here for the div. Save again. Let's check out our page here. It says we have to do a full page refresh. Okay. And you can see that the background is red, but for the other pages, say about, that style should not apply. And it doesn't.

Head Tags and Layouts6:22

Head from next. And within here, you can add any head tags that you would usually add. So for example, a <title> tag. Let me just close this. Let's add a <title>. Let's say my next app. And now this page should have this title. So let me save this. Let's go to that page. So it was a specific posts page.

Let's go to that page. So it was a specific posts page. So posts/1. And now you can see the title applied to that page. Now if you wanted to make use of layouts, you can do that as well. There's support for single layouts or also multiple layouts. We'll take a look at a single one for now. So within the app.js, we can just wrap our entire app in a layout component. And then every page should make use of that. So let's go ahead and do that.

And then every page should make use of that. So let's go ahead and do that. Let's grab this layout component, which we will create. Let's go to app.js here. Let's wrap our component in that layout. So let's say layout. We will create that in a second. Let's make a new components folder that has this new component or this new layout. So let's say components/layout.jsx. And within here, we can create our layout.

So let's say components/layout.jsx. And within here, we can create our layout. So let's say React functional component. Let's say this is the layout. Let's save that. Let's make sure to save app as well. Actually we have to import layout here. So let's do that. Okay. Hopefully that imported.

Okay. Hopefully that imported. It did. Save that. Let's see if it works. And you can see the layout did show, but it's not showing our actual page content. So within our layout, we have to grab the children. So we can destructure it from the props here, say children, and then we can render the children anywhere in our layout. So let's just put it in another div here.

anywhere in our layout. So let's just put it in another div here. So let's say div, children, close that div out. And hopefully that works. Let me save this. Let me actually wrap this in a nav. Save that. And hopefully the page content renders now. And it does. Cool.

And it does. Cool. So there's the layout. Let's go back to our main page here, see if that works as well. And the layout seems to be working for every page here. Let's go ahead and add a navigation for our pages that we have so far. So to link to pages, we can make use of the link component. So very similar to router links using React Router. So let's do that within this nav element. Let's make use of the link component.

Server-Side Data Fetching9:36

We can do it the traditional way using client-side rendering. So for example, you can use a useEffect hook with useState. And you can fetch your data the traditional way using fetch or Axios. Or you can make use of a dedicated fetching library like SWR or React Query. Or you can fetch your data on the server, which we'll be taking a look at here. We'll start with server-side rendering. And for that, we can make use of the getServerSideProps method. So let's go into here. Let's grab this. And remember, this call happens on the server side.

Let's grab this. And remember, this call happens on the server side. And whatever you return here in the props will be available as a prop to the component. So in our case, we want to go to our posts page. So this page right here. Let's grab some posts from an external API and show them here. So let me paste in that method. Again, this happens on the server. Whatever gets returned here, you can make use of in this component in the props. So let's accept that in here.

Whatever gets returned here, you can make use of in this component in the props. So let's accept that in here. And let's go ahead and fetch some posts. So for this, I'm going to make use of the JSONPlaceholder API. There should be an endpoint here for posts. So let me just scroll down. Posts right here. So let me just open this up. And by default, it shows 100 posts, I believe. But you can limit that with this query string.

And by default, it shows 100 posts, I believe. But you can limit that with this query string. I believe it's called _limit. And you can set a limit here. Now we should only have 10 posts. And we can make use of this endpoint. So let's go back to our code. Let's go ahead and fetch those posts. So within here, again, this happens on the server side. And we can make use of fetch on the server side here.

So within here, again, this happens on the server side. And we can make use of fetch on the server side here. Say const response equals await. Make use of fetch. Let's grab that endpoint. And I'm not too worried about errors here. Let's just grab the response. So say const posts equals await response.json. And that should be our list of 10 posts. So we can pass this in as props here.

And that should be our list of 10 posts. So we can pass this in as props here. So let's say posts. Now this component should have access to it within here. And we can list them out in our page here. So let me just wrap this in a <p> tag. And we'll make another element here to list our posts. So let me just make an unordered list here. And we can map over our posts here. So I'll say posts.map.

And we can map over our posts here. So I'll say posts.map. Let me destructure post here instead of grabbing the props posts. And for each post, we can just show the post.title. So let me grab this, put it after here. Let's say post.title within the list item. I believe I'm missing an extra bracket here. And I think I need a key in here. So we can say key equals post.id.

And I think I need a key in here. So we can say key equals post.id. Or sorry, post.id, like this. OK, let me save that. And let's see if the posts are shown on our page. So back to our app. Let's go ahead and refresh. And everything is showing here. So again, in this case, we're making use of data fetching on the server.

So again, in this case, we're making use of data fetching on the server using server-side rendering. So this call happens on the server. Whatever we return in the props gets passed to our component. And then we can do whatever we want in here. In this case, we're just showing it. So let's go ahead and do this on the single Post page as well. So within here. The endpoint for that should be /post/{id}.

So within here. The endpoint for that should be /post/{id}. So within here, we can just say post/1 or whatever. And that should work. We have a title and a body. So let's go ahead and work on that. So pretty much the same thing. Let's grab that from our index. We get server-side props. Let's go to our ID here.

We get server-side props. Let's go to our id here. Let's paste that in. Let's go ahead and update the endpoint here. It's going to be posts/{id}. And that's coming from the URL. So in this case, we can grab it from the context here instead of the router. So context.params.id. This should be a Post now.

So context.params.id. This should be a post now. We can return the post in our props here. And then within our component, let's accept that. Let's destructure it here. Let me just make another div in here. This will be for the title. Let's make an h2. So it should be post.title. And let's make a section for the body.

So it should be post.title. And let's make a section for the body. Let's say post.body. Let's save that. And let's see if this works. So let's go back to our app. Let's go to a single post page, say /1. And it does work. Cool. Let's go ahead and update our PostsComponent.

Cool. Let's go ahead and update our PostsComponent to link to the specific Post. So back to index. Within here, let's make a link tag. link href equals. And it should be /posts/{postId}. Let's close that out. Make sure to close the link tag here. Make sure to import link as well.

So if you wanted to add the title within the actual title tag here, you can do that as well. So within here, we can say post.title. And then the actual title. And that works. Cool. Now again, for these two examples, we're making use of getServerSideProps,

Now again, for these two examples, we're making use of getServerSideProps, which pre-renders our pages using server-side rendering. So whenever a request comes in, the data is fetched server-side and the corresponding page is rendered dynamically. So think of it as a traditional request to a server-side language like PHP. So as I visit one of these pages here, so I'm a User. I go to this page. A request is made.

I go to this page. A request is made. It goes into this method here. We fetch the data server-side. We pass the data to our component here. And then it's rendered on the page. Now like I said earlier, the alternative way of pre-rendering our pages is to make use of static site generation. So let's take a look at that way now.

Static Generation and Export16:36

So now if I'm a User of the application, even before I hit this route, there should be static pages already generated for this specific page. So let's go ahead and convert this over. So we'll start with the index page here. So like I said, even before I hit this route, there should be a .html page that is already pre-built. And then once the User makes a request, that static HTML file is served to the User.

And then once the user makes a request, that static HTML file is served to the user. So let's make use of getStaticProps. So let me grab this method. Actually, it's the same thing. It's just a different name. So let's go back to our index here. I am going to leave this in, but I'll just comment it out. Let me comment this out. Let's comment, or let's copy it first, or duplicate it.

Let me comment this out. Let's comment, or let's copy it first, or duplicate it. And let's comment this out. Now it's called getStaticProps. getStaticProps. And for this case, this is the only change we need. So now at build time, this method will be run. This data is fetched from this API. And then a corresponding HTML page will be generated. So let's go ahead and save this.

And then a corresponding HTML page will be generated. So let's go ahead and save this. Now what you see in the browser will be exactly the same. So if you go to /posts, let's do a full page refresh. This still works. You're not going to see any difference on the dev server, but hopefully the next example I show you for the single page post will make more sense. So let's go to the single page post. Again, right now we're making use of server-side rendering.

So let's go to the single page post. Again, right now we're making use of server-side rendering. So in here. But let's change it to getStaticProps instead. So again, I'm going to duplicate this. Let's comment this one out. And let's change this to getStaticProps. And in this case, we should get an error. So I'm going to save this. Let's refresh.

So I'm going to save this. Let's refresh. And we get this error here. It says getStaticPaths is required for dynamic server-side generated pages and is missing for posts/ID. So if you take a look at the docs here, for getStaticProps, actually it's within getStaticPaths here. It says if a page has dynamic routes

actually it's within getStaticPaths here. It says if a page has dynamic routes and uses getStaticProps, it needs to define a list of paths to be statically generated. So we are using a dynamic route in this case. So we need to define that method as well. So I hope this is starting to make more sense to you. Now that we're using getStaticProps, it needs to generate the pages beforehand,

now, when we use SSR beforehand, we didn't need to do this because the page is generated upon request. But now that we're doing it on build time, we have to specify which pages we want to generate. So let's go back to the docs here. We have to define this method as well, getStaticPaths. So let's put it underneath here. And within this paths array is where we want to define the pages we want to generate.

And within this paths array is where we want to define the pages we want to generate. So the format in this case, it's going to be params, and we just need the ID and the ID has to be a string. So in this case, it's just one. And I think I have too many braces here. So say, for example, I want it to generate posts one, two, and three. Then we have to specify it like this, one, two, and three.

Or I think we have to add an option for that. The fallback should be false if we want a 404 for anything that we didn't specify within this paths array here. So let's change this to false. Let's save this. Let's try to hit 404 here. And we do get a 404. So I hope that makes sense. Now we just have to dynamically generate the paths array.

So I hope that makes sense. Now we just have to dynamically generate the paths array. So let's grab this endpoint here. But we don't need a specific post. We just want the endpoint that shows all of our posts. So this post or posts endpoint. Actually, let's grab it from our posts page here. It's this endpoint. And we limit the posts to 10 here, which is fine. Let's paste that in.

And we limit the posts to 10 here, which is fine. Let's paste that in. Let's grab the posts. So await response.json(). And let's start with just the IDs here. So let's say const IDs equals posts.map. And let's just grab the id. So let's say post => post.id. So there should be an array of IDs for our posts. We can say console.log(IDs) if we want to see that.

So there should be an array of IDs for our posts. We can say console.log(IDs) if we want to see that. And hopefully this shows up in here, and it does. So we have posts one through 10 here, okay? And remember, we want it in this format here. So we have to do another map here. So say const paths equals IDs.map. And for each ID, we just want to return that format there. So let's say params, basically this. So I'm going to grab one of these.

So let's say params, basically this. So I'm going to grab one of these. Let's paste that in. And we should have the ID. And like I said, there has to be a string. So ID.toString, okay? Hopefully I did that right. So let me just leave this in here. But we'll pass in the paths here. Okay, should be a comma.

But we'll pass in the paths here. Okay, should be a comma. And hopefully I did that correctly. Again, we have to do it this way so it knows to generate post1.html all the way to post10.html, okay? Let's save this. Let's see if one to 10 works. So three works. Let's check if 10 works.

or we can use static site generation and generate all of our pages at build time. Again, depending on your pages and your needs, you can mix and match both approaches. However, if your entire site is statically generated, let me show you how you can export that. So let's go back to our package.json. Let's make a new script here for exporting. So I'm gonna copy this.

Let's make a new script here for exporting. So I'm gonna copy this. Let's paste this in. And let's add next export. So this will build our site. Actually, let's name it export here. So this will build our site and also generate an out folder with all of our static HTML. So let's save that.

with all of our static HTML. So let's save that. Let's run this. I'm gonna stop my server here. Let's say npm run export. And we are getting an error with useRouter here. Let's take a look at what's going on. So that's within here. I believe it has to do with my name. So let me just rename this to in uppercase P.

I believe it has to do with my name. So let me just rename this to in uppercase P. That seems to have fixed it. Let's try that again. And you can see here React component names must start with an uppercase letter. So let's try that again. And we're getting another error here with image optimization. And I think that has to do with the Image component that's being used in the Default component.

And I think that has to do with the Image component that's being used in the default component. So within here, where is it? Index. And I'm just gonna rename this to index.jsx as well. We are making use of this Image component, which I didn't go over. It's a Next component that has extra features for handling your images. And it's used one time down here,

for handling your images. And it's used one time down here, but I'm just not gonna use it here. So let me comment this out. And let's try that one more time. Hopefully it works this time. Okay, so it looks like it did work this time. So back to our code. So this .next file or folder is what you would use to deploy.

So this .next file or folder is what you would use to deploy. But we also have this out folder where all of our static files live. So if you take a look at here, you'll see all of our static pages that we generated and also this posts folder. And you can see we have the 10 generated pages for each post here. So if you just run any server that can handle HTML files,

for each post here. So if you just run any server that can handle HTML files, then we should be able to see our site in the browser. So let's go to the out folder. I'm just gonna run my php server here, but any server will work. So I have an alias name server. Let me just show you that, which runs a php server in the current folder and runs it on localhost:8888.

which runs a php server in the current folder and runs it on localhost:8888. So let's run that. Okay, it's running. If we go to that in the browser, you'll see here is the application that we created. So here's the main page. The other static pages that we had and also our posts page. Here are our posts that were generated on build time.

Installation and basic usageExample of pre-rendering using server-side renderingExample of pre-rendering using static site generation

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟