8 December 2020
Server-Side Rendering with Next.js
Next.js is a production-ready framework built on top of React that provides advanced functionality, such as Server-Side Rendering.
Prerequisites:
Some React experience Node.js 12+ Yarn 1.22.0+ Npm and Npx
Why Next.js
As a React site scales in size so will some of the challenges facing a modern web application. Here are some of the issues you and your team may be facing:
Your Javascript bundle size is way too large, causing performance issues on older computers and mobile devices, but using webpack or another bundler along with a compiler like Babel becomes cumbersome and confusing. The application needs to be more SEO friendly, content should load faster for your users and for Google’s Crawlers. You need real user feedback and analytics to improve your User Experience.
Server-Side Rendering (SSR) is a popular technique to address some of the above issues, but it can be a pain to implement yourself. This is where a framework like Next.js really shines. It presents solutions to these problems(and others) while providing a top-notch developer experience. I want to focus on Next.js’ approach to SSR, or what they call “Pre-Rendering” .
Pre-Rendering
Next.js uses the concept of Pages as the building blocks of your application. By default, each Page in the /pages
directory is served pre-rendered. This means by the time your code reaches the browser it is a fully formatted HTML document. This can provide significant improvements in performance and make your page more discoverable for SEO purposes. This is all fine when working with static content, but what about the common scenario of fetching data from an API or database to render your components? Next.js offers two forms of pre-rendering with fetched data, Static Site Generation(SSG) and Server-Side Rendering(SSR), we’ll take a look at each in a bit more detail.
Static Site Generation
Static Generation is Next.js’ preferred method of Pre-Rendering. In this scenario, data is fetched and HTML pages are constructed at build time, allowing pages to be cached and reused on subsequent requests. This method is ideal for the situation when your data is not dependent on a specific user request. Next.js allows you to perform Static Site Generation by exporting an async function called getStaticProps
. Let’s take a look at its usage.
You can follow along by referencing the Getting Started documentation. To quickly create a Next app, type this command into your terminal:
npx create-next-app your-app-name
Then cd
into your app’s directory and start it in development mode with yarn dev
.
For this example, let’s create a file in our /pages
folder called AlbumsListPage.js
that we will use to display a list of albums by our favorite musical artist. The API requires an artist id, I’ve abstracted the implementation details for clarity.
function AlbumListPage({ albums }) {
return (
<ul>
{ albums ? albums.map(album =>
<li>
<h1>{album.name}</h1>
</li>) : null }
</ul>
)
}
export async function getStaticProps() {
const response = await fetch(`https://api/.../artists/${id}/albums`)
const albums = await response.json();
return { props: { albums }}
}
export default AlbumListPage;
There are a few important points to make here. First, I want to stress that getStaticProps
must be exported from a component in the ‘/pages’ directory, otherwise, it will not be recognized by Next.js. Second, notice we preface getStaticProps
with export
and async
. This function returns an object, which is required to contain a props object which we pass our list of albums, and we can then access albums
via props just like any other React component.
Server-Side Rendering
In other cases, data needs to be updated on a user’s request such as a search, or we have data that updates on a frequent basis. For this situation, we can use Server Side Rendering to fetch data on a request but still serve a full up-to-date HTML Page. The code is very similar to our SSG example, except this time we export
an async
function called getServerSideProps
.
function AlbumListPage({ albums }) {
return (
<ul>
{ albums ? albums.map(album =>
<li>
<h1>{album.name}</h1>
</li>) : null }
</ul>
)
}
export async function getServerSideProps() {
const response = await fetch(`https://api/.../artists/${id}/albums`)
const albums = await response.json();
return { props: { albums }}
}
export default AlbumListPage;
You’ll notice that the implementation is almost identical to that of getStaticProps
, with the same requirements as an export async
function from the /pages
folder. However, the main difference is getServerSideProps
is called on each request for our page instead of at build time. Although this method is slightly slower than Static Generation, it ensures we always have the most up-to-date props.
Summary
Next.js is a powerful, easy to use framework that prepares your React app for production at scale. We’ve looked at one of it’s most useful and popular features in Pre-Rendering:
Static Site Generation - This should be your main method for fetching data when it can be performed prior to a user’s request. Ultimately, this provides the best performance with cached Pages and makes your site more SEO friendly. Server-side Rendering - Ideal when you still want to pre-render your Page’s HTML, but the data must be fetched at request time. The performance will be slower than SSG and may require placeholder elements to eliminate layout jumpiness while the data is fetched.
Next.js allows you as the developer to decide on a Page by Page basis which method of Pre-Rendering you’d like to use depending on your application’s needs. It is also worth noting that if your site requires Client Side Rendering, the Next.js team has built a custom React hook called SWR specifically for this purpose.
In addition to Pre-Rendering, Next.js offers solutions for Image Optimization, Routing and Navigation, Typescript support, Analytics, E-commerce, Code Splitting, and Bundling, all with minimal to no configuration. Find out more at nextjs.org.