Next.js (work in progress)
Next.js - 2. Pages and pre-rendering
Updated:
What you'll learn
In this article you will learn the following:
- How pages work in Next.js
- How to create dynamic pages and routes
- Two different ways to pre-render pages, static generation and server-side rendering
- How to create static pages with data using
getStaticPaths()
andgetStaticProps()
Pages
A page in Next.js is a React component placed inside of the /pages
directory. To understand how this works, within the app you created in the previous article, create a file called posts.js
inside the pages/directory
.
Inside this file, add the following:
function Posts() {
return <h1>Posts</h1>
}
export default Posts
Start up the local dev server with:
npm run dev
Then open http://localhost:3000/posts
in your browser.
You should see the following:
That’s how easy it is to create pages in Next.js. All you have to do is export a React component from the /pages
directory!
Dynamic routes
Our posts page is perfectly fine, but what happens when we want to render pages dynamically? For example, if we were building a blog with Next.js, how would we dynamically generate a page for each blog post?
This is where dynamic routes come in.
You can create pages that support dynamic routes by using a special bracket syntax in the filename of your page. For example, pages/posts/[id].js
. This special syntax, [id]
, allows users to access posts with the following URLs.
posts/1
posts/2
posts/3
- etc.
You can use whatever name you like within the brackets. I am using “id” in this example, but you can use anything you want.
You will see a working example of dynamic routes shortly.
Pre-rendering
Next.js handles two types of pre-rendering, static generation and Server-side rendering or SSR.
- Static generation - means that the HTML is generated at build time. Think of this as being similar to what a static site generator does.
- SSR - means that the HTML is generated upon each request.
What makes Next.js unique and incredibly powerful is that you can choose the type of pre-rendering you would like to use per page! This means you can have some pages that are statically generated and others that are SSR.
The creators of Next.js recommend static whenever possible because static pages load faster and are better for SEO. If you have highly dynamic pages that change on each request, SSR is the better choice.
The beauty here is that you can pick and choose which rendering method you want on a per-page level which means a better experience for your users.
Dynamic routes in action
Dynamic routes can be tricky to wrap your head around, so let’s see an example. We will create a simple blog by fetching some dummy post data from JSON Placeholder.
First, create a new folder inside of the /pages
directory called posts
Next, move the posts.js
file inside the pages/posts
directory and rename it to index.js
.
Everything should be working the same, so when you go to http://localhost:3000/posts, you should see the following still:
Next, create a file called [id].js
inside of the pages/posts
directory.
Static generation and data
We want to dynamically create our pages based on the id of each post. To do this, we are going to use two functions provided to us by Next.js called getStaticPaths()
and getStaticProps()
.
I will show you the code first, and then we will break down everything line by line.
function Post({ post }) {
return (
<>
<h1>{post.title}</h1>
<p>{post.body}</p>
</>
)
}
export async function getStaticPaths() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}))
return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${params.id}`
)
const post = await res.json()
return { props: { post } }
}
export default Post
First, let’s take a look at the Post
function.
function Post({ post }) {
return (
<>
<h1>{post.title}</h1>
<p>{post.body}</p>
</>
)
}
This function is solely responsible for displaying the post data returned from the API. It receives a post parameter from the getStaticProps()
function. More on that in a moment.
getStaticPaths
Next, we have the getStaticPaths()
function.
export async function getStaticPaths() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}))
return { paths, fallback: false }
}
It can be helpful to use console.log()
to log out the variables to better understand what is happening.
Inside this function, we are fetching the posts from our API.
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
Then, we convert the response into a JS object.
const posts = await res.json()
Next, we map over all of the posts and return an array of objects. Each object has a params
property and the id
of the post.
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}))
If you console.log()
the paths variable, you will see the following in your terminal.
export async function getStaticPaths() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}))
console.log(paths)
return { paths, fallback: false }
}
Finally, we are returning the paths
variable and fallback: false
. Remember that the paths
variable is an array containing a bunch of objects with a params
property. This is then passed into getStaticProps()
to fetch the data for each post.
fallback: false
means that any other routes or paths will throw a 404 error.
return { paths, fallback: false }
getStaticProps
Finally, within the getStaticProps()
function, we have the following:
export async function getStaticProps({ params }) {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${params.id}`
)
const post = await res.json()
return { props: { post } }
}
We are getting the post data from our API just like in the getStaticPaths()
function, only this time, we are returning an object with the property of props
which contains the post data for each of our posts. If you console.log()
the post
variable, you should see the following in your terminal.
If you open the following URL in your browser, http://localhost:3000/posts/1, you should see the following:
Now, if you change the URL to /posts/2
or /posts/3
etc., you will see the respective post.
Server-side rendering
If you are rendering content server-side, then instead of using getStaticProps()
, you use getServerSideProps()
instead. Since they work similarly, I won’t cover it in this tutorial. You can read more about server-side rendering here.
Wrap up
In this article you learned the following:
- How pages work in Next.js
- How to create dynamic pages and routes
- Two different ways to pre-render pages, static generation and server-side rendering
- How to create static pages with data using
getStaticPaths()
andgetStaticProps()