Next.js Fundamentals —Data Fetching

Sparsh
6 min readMar 9, 2021

If you’ve worked with making websites interactive with vanilla JavaScript or jQuery in the past, chances are you already know the struggle of building and maintaining such applications. With the advent of frameworks like React, Angular, Single-Page Applications(SPA) have almost become a norm. In a SPA, the server responds with a minimal HTML that consists of a link to the bundle file which holds all the code to render the dynamic content and make the page interactive. We call this mechanism Client-Side Rendering(CSR), simply because the client is responsible to parse the JavaScript and compile it to valid HTML which gets rendered in the browser. While in most cases it’s a perfect solution but then in some cases, it is not.

If you are looking for good SEO for your page, you will have a hard time convincing the crawlers. If you are targeting low-end devices and your code is not split, you will almost have a blank page for most of the time your user is on the site. And you’ll end up trying all kinds of hacks to get the social sharing working. So, of all these years of hassle what’s the solution? Next.js!

From its official documentation,

Next.js is the React Framework for Production.
Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed.

In this post, I am aiming to paint a big picture of how the various rendering mechanisms for data fetching work and how Next.js embraces them. This post is specific to the data fetching part of Next.js. For other topics, please refer to the documentation.

Note: We are not going to get into the details of Client-side Rendering because it not something specific to Next.js but we will instead dig deeper into Pre-rendering mechanisms that Next.js provides.

We will be using https://jsonplaceholder.typicode.com/ as the external APIs.

Static Generation

Simply put, Static Generation is applying multiple data, content to a template and serving them as separate views to the client.

Say you had a blog with around 100 posts, there is no way you are going to create 100 equivalent files for these blogs with their own set of markup and styles. What you’d instead do is create a component that takes in the post and creates the UI basis of the available information. Say our posts are in this shape:

{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},

Next.js follows filesystem-based routing, which means any file that you create under the pages/ directory will be available as a separate route. You can read more about it here https://nextjs.org/docs/basic-features/pages.

getStaticProps()

Inside the pages directory, we have posts-ssg.js which looks something like this:

We use getStaticProps to inform Next that we intend to use Static Generation for this page. Ok, but what does that even mean?

  • Because we are using pre-rendering, Next.js at build time will compile our javascript into HTML — a valid HTML with the list tags and not just a skeleton HTML with a link to the bundle file.
  • When the client(Browser) requests for the page to the server, it will respond with a compiled HTML and link to a Javascript file that will make this page interactive. The browser then renders this HTML, parses CSS, and compiles the accompanying JavaScript(This is also called hydration).
http://localhost:3000/post-ssg | Network -> Preview tab

If you look at the networks tab and the preview of the server response, you will notice that it indeed responds with a valid HTML and not a blank page unlike Client-Side Rendered pages. So now search engine bots when crawling through your sites, won’t be bummed by a blank page but will instead see a readable HTML. This is why Next.js is so popular for SEO purposes.

So far so good, but what happened to the 100 pages that we were going to generate? Enter getStaticPaths!

getStaticPaths()

getStaticPaths allows you to specify paths for which HTML has to be generated at build time. Take a minute to understand the model, no more just dynamic content on the same page instead we will have 100 HTML files after the build.
Continuing the posts example, if we had pages for each posts posts-ssg/1, posts-ssg/2, ... we will create posts-ssg/[id].js directory. With this posts-ssg/1 will have { id: 1 }in router query parameters.

getStaticPath will return an exhaustive list of possible posts and pages will be generated for these returned params. getStaticProps will receive the post id in params, fetches post detail, and return the post as a prop to the component.

http://localhost:3000/post-ssg/12 | Network -> Preview tab

Notice how the preview includes the post title and body in the response. During development, this might look like no magic, but at build time 100 static HTML files will be generated for these posts.

Upon running npm run build all of our posts are compiled into their HTML files.

Files generated via npm run build
File statically generated | posts-ssg/12.html

This was Static Generation in action. There are a lot of articles out there that point of the pros and cons of SSG, the thumb-rule I follow is: If you know ahead of time the pages that have to be generated, and can afford re-building numerous pages on every change go with SSG. Things like documentation, landing pages are barely updated frequently so SSG is a good choice there.

Server Side Rendering

In Server Side Rendering the server still responds with a valid HTML just like SSG, but the HTML is generated at the time of request and not at build time like SSG. The server receives a request from the client(Browser), looks at getServerSideProps for fetching the data required to build the page, generates an HTML, and sends back the compiled HTML with relevant JavaScript and CSS.

Let’s assume that we did not have the post files generated from our previous example, how would we pre-render them with SSR?

getServerSideProps()

For a page to server-side rendered, we export getServerSideProps function which returns a value that will be used to build HTML on the server.

http://localhost:3000/post-ssr | Network -> Preview tab

The preview tab still displays the HTML like in the case of SSG, but this HTML was built at the time of request and it wasn’t available until the client requested it. This is what makes SSG and SSR different.

If you look at the build files now, posts-ssr does not hold anything about the posts. It does not even generate a static HTML file. This shows how SSR builds the pages at the time of request rather than at build time.

File generated for server-side rendered page

With SSR it becomes super simple to Pre-render dynamically changing content without having to worry about build times or having to re-build frequently. But, the catch here is the server response time will be high since the server will have to generate the HTML for the response(referred to as Time To First Byte in lighthouse metrics).

The methods discussed above also have other parameters and return values. You can refer the API spec in the Next.js documentation.
This is it, for now, will soon be back with another article on how to use redux with Next.js. Thanks for reading through, feedback and corrections are highly appreciated.

--

--