NextJS Different Data Rendering Modes and Their Functions


NextJS is the most popular way to build React applications and it’s being used by a lot of businesses and enterprises. With NextJS you build your application locally and push it to git where you are able even to preview the changes and get the live deployed URL. With the four data rendering modes this framework gives an effortless and an easy experience to work about.

The most current version of NextJS is version 10 at the moment and it supports four rendering modes:

• CSR: Client Side Rendering
• SSR: Server Side Rendering
• SSG: Static Site Generation
• ISR: Incremental Static (Re)-Generation

Client Side Rendering is what actually React uses. Basically, there is a server with markup, a database and the client which is of course the user.
So, in client side, rendered markup is sent to the client and then data is fetched from the database. In React this process is accomplished with something like "useEffect" or "useState". As a result, a blank page is sent to the client and then data is fetched and the page is rendered.

Client-side rendering when it comes to SEO has some disadvantages as that means if the user requests the data, first the markup is served and then only then it is asked for the data.
According to NextJS docs page it is recommended to use SWR React Hook if you are fetching data on the client side as it handles caching, revalidation, focus tracking and re-fetching on interval. It can be used like this:

import useSWR from 'swr'
function Profile() {
  const { data, error } = useSWR('/api/user', fetch)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>

Server Side Rendering works by first fetching the data to the markup in the server and after that the bundle is sent to the client. For every request that the client makes, the file will be sent again, meaning that if the client refreshes the page, the process will be undergone again as aforementioned. Therefore the data will be fetched from the database to the server and then the completion will be sent to what the client requested. As a result, using Server Side is quite convenient when you want to fetch the data every time it is requested which makes sure you have the most updated data. The code block below shows how NextJs uses it.

//Server Side Rendering 
export default function ServerSideRendered({ state}) {
  return (
     <ul>
      {state.map((st) => (
        <li>{st.title}</li>
      ))}
    </ul>
  );
}

// fetching data on each request
export async function getServerSideProps() {
  const res = await fetch('<YOUR_API>');
  const state = await res.json();

   if (!state{
    return {
      notFound: true,
    }
  }   

  return {
    props: {
      state, // will be passed to the page component as props
    },
  };
}

Notice that the async function getServerSideProps gets exported from a page and then Next.js will pre-render the page on each request using the data returned by getServerSideProps.

Static Site Generation is the fastest way you can serve a markup. This method includes changing or adding data in the markup and these changes are done mostly on our local machine and we push those changes to git and that will trigger a rebuild of the site. While in the process of rebuild, the data is fetched and is ready on the markup as a Static Site and it is served to the client.
Basically, the data is fetched statically at build time and it is sent as a pre-build to the client, so if the client refreshes the page there is no need to fetch it again as the data is already fetched inside the markup. The advantage compared to server-side rendering is that in static site rendering there is no need to fetch the data every time a page refreshes. As a result, all the data that is requested is already done beforehand.

// static site generation
function StaticSideGeneration({ state}) {
  return (
     <ul>
      {state.map((st) => (
        <li>{st.title}</li>
      ))}
    </ul>
  );
}
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export async function getStaticProps() {
  const res = await fetch('<YOUR_API>'); 
  const state= await res.json();

  return {
    props: {
      state, // will be passed to the page component as props at build time
    },
  };
}

export default StaticSideGeneration

Incremental Static Site (Re)-Generation

Permalink to "Incremental Static Site (Re)-Generation"

Incremental Static Side (Re)-Generation provides a hybrid approach of Static Site & Server-Side features. It is introduced in NextJS 9.5 version and up.
It comes with the getStaticProps method which allows the static content to be dynamic with allowing to update the current pages by re-rendering them in the background without interruption coming from static storage and the newly built page is pushed after it is done generating. While re-generating the page, if it fails in the background, then this will not affect the old page as it will remain unaltered.

Basically, the data is generated statically and has the bundle ready for the client to be returned as fast as possible, so we don’t have to fetch the data when the client refreshes the page but the page can be re-build with an interval. So, if there is an interval of 5 seconds, then we will tell NextJS server to rebuild this page every five seconds so it can help on the page to be updated. So, every 5 seconds you have a prebuild page and you can serve that page to the client without having to fetch it again. This can be approached with revalidate option which with every request that comes in, at most once every 5 seconds it re-generates the page. Whilst revalidating, the client can see the cached version and only then the updated one. If it is pre-build it still behaves as a static site so you can serve up the markup and the data as one bundle without having the client to request anything else.

// Incremental Static (Re)-Generation, Source: Next.js Docs 
function IncrementalStaticGeneration({ state }) {
  return (
   <ul>
      {state.map((st) => (
        <li>{st.title}</li>
      ))}
    </ul>
  );
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in

export async function getStaticProps() {
  const res = await fetch('<YOUR_API>'); 
  const state = await res.json();
  return {
    props: {
      state, // will be passed to the page component as props
    },

    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most every 5 seconds
    revalidate: 5, 
  };
}

export default IncrementalStaticGeneration

According to NextJS docs the getStaticProps should be used when the page must be pre-rendered (for SEO) and be very fast. It generates HTML and JSON files, both of which can be cached by a CDN for performance. Also, when the data comes from a headless CMS and is required to be rendered at build time ahead of user’s request. In addition, the data is not user-specific and can be publicly cached.

Which approach is better suited?

Permalink to "Which approach is better suited?"

Depending on the rendering mode and how they work, these approaches might be applied based upon the project.

CSR: Client Side Rendering is done when the SEO is not so important, when there is only a dynamic page, something like an admin of some app like an accounting program or user-specific dashboard pages. That means that the data is frequently updated with request-time data fetching rather than pre-rendering.

SSG: It is great for SEO and is used mostly as a default option, something like a blog that doesn’t change often, like a service page and to make sure that the page loads as fast as possible.

ISG: when you have a more dynamic blog or when you need to change some things on the product page or projects.

SSR: should be used when there is quite dynamic data, something like reddit or e-bay, where data changes very often.