Introduction
Next.js is the most popular and easiest way to build React applications. It includes a number of functionalities that you need to use in your React application. One of these functionalities is pre-rendering. Pre-rendering is one of the core concepts involved in data fetching in Next.js.
Pre-rendering
Pre-rendering refers to the process whereby Next.js prepares HTML for each page in advance instead of client-side JavaScript doing it entirely. In a React app, the JavaScript loads and executes to mount the HTML element onto the DOM. So when the page is served, we have only a div tag with an id equal to root. Once the JavaScript for the page is loaded, it will execute in the browser, create different DOM nodes, and mount them onto the root div element. Another name for this process is hydration. By default, Next.js pre-renders every page in the application. In other words, the HTML is generated with the required data and sent to the browser. Then the JavaScript would load and make the page interactive, but the HTML is already present at first. So, "pre-rendering" means rendering before sending it to the browser.
Importance of Pre-rendering
We have a significant concern with the fact that Next.js includes pre-rendering as a standard feature. We should pre-render pages in an application, but why? Two crucial factors will help us respond to this query.
First, pre-rendering improves performance. In a React app, you need to wait for the JavaScript to be executed, which would then fetch data and render the UI. So there is a wait time for the user, who can, to a certain extent, be pacified by showing a loading indicator. However, with a pre-rendered page, the HTML is already generated, and hence, the page loads faster.
Second, pre-rendering helps with SEO. With a React app, if the search engine hits your page, it only sees a div tag with an id equal to root. But if the search engine hits a pre-rendered page, all the content is present in the source code. This will help
index that page, leading to better search rankings.
Data fetching
Data fetching in Next.js enables the rendering of information in a variety of ways. These include rendering beforehand using static-site generation or server-side rendering, as well as updating using incremental static regeneration.
Static-site generation
Static-site generation is a method of pre-rendering where the HTML pages are generated at build time. The HTML with all the content that makes up the the web page is generated in advance when you build your application. This is the recommended method to pre-render pages because the page can be built once, cached by a CDN, and served to the client almost instantly. This leads to a huge performance boost for your application. Static-site generation is useful when building blog pages, e-commerce product pages, documentation, and marketing pages. Next.js by default, with no configuration, statically generates every page in our application when we build it for production. This allows the page to be cached by a CDN and indexed by a search engine. The method Next.js uses for static-site generation is getStaticProps.
Problems with static-site generation
With static-site generation, you generate pages using getStaticProps when you build the project. But in doing this, we come across some problems.
The first problem is that we cannot fetch data at the requested time. With not being able to fetch data per request, we run into the problem of stale data. For instance, if we want to build a news website, the content will be dynamic because new articles can be published almost every second. Given the content of such a website, we cannot afford to have stale data. getStaticProps will fetch the news at build time, which is not suitable. To solve this problem, Next.js introduced the concept of incremental static generation. With static-site generation, there was a need to update only pages that needed a change, without rebuilding the entire application. With incremental static generation, Next.js allows you to update static pages after your application is built. This means you can statically generate individual pages without needing to rebuild the entire application, effectively solving the problem of dealing with stale data.
The second problem is that we don’t get access to the incoming request pre-rendered at build time. This becomes a problem when the data that needs to be fetched is specific to a user. Let's say we are building a website similar to Twitter. To fetch tweets specific to the user, we need the userId. And that can be obtained if we have access to the incoming request. For example, the userId can be part of request cookies, which we can extract and use to fetch data specific to that user. Without access to the incoming request, it becomes difficult to build a page similar to a Twitter feed.
With static-site generation, the build time is proportional to the number of pages in the application, so larger applications would take longer to build and render. This requires time and has financial repercussions as well. As you add more products to the system, the build time problem only becomes worse because each new page adds to the overall build time.
Server-side Rendering
With server-side rendering, Next.js enables you to pre-render a page at a requested time rather than during page build. For each incoming request, HTML is generated. Server-side rendering is useful when you need to retrieve customized data while keeping SEO in mind. To use server-side rendering for a page in Next.js, you must export the getServerSideProps async function. When you export this function, the server will use it for each request. This and getStaticProps are pretty similar.
With server-side rendering, the server serves up a new HTML document on each request. The browser loads and parses CSS to paint the UI. The browser then loads and parses JavaScript to enhance the UI. This means the user sees something on the screen while the page is still loading. The server-side-rendered apps also appear to run well; for the user, the initial load time would be quicker because the browser would paint the DOM after acquiring the HTML and CSS files. It does not have to wait to parse or load JavaScript before it can show the user something useful. So, the user will believe that the program is operating more quickly, which also enhances SEO.
Problems with server-side rendering
The first disadvantage of server-side rendering is the increased load on the server, and that is because every single time you request a page, the server will have to generate new markup for that request.
Also, server-side-rendered applications often have latency because of multiple back-and-forth page requests and page reloads.
Server-side-rendered applications also have low UI/UX interactivity. They rarely have that "native" application feel. This also has to do with page reloads.
Conclusion
Based on the use case, you can now select the best Next.js data fetching approach for your application. It is good practice to always check if we can statically generate any data because it is faster. Pre-rendering offers several benefits; one major one is performance improvement, as the website will render more quickly because it has already generated the content. Also, SEO crawlers can easily find and rank the page content.