When I started to learn Next.Js, I felt a little bit lost with some abbreviations they use to make the data fetching. All of them look pretty simmilar, but they have different meanings. If you feel the same, you are not alone. Let's discover what CSR, SSR, SSG, and ISR means, and how we can use them.
It is quite confusing because I, as an Angular developer, only knew one strategy to fetch the data:HttpClient. But for example, if you are more familiar with React, you probably use a different strategy: useEffect
.
So, let's get started. Vercel's Next.js framework has four different data fetching options despite being known as a server-side render framework:
- CSR - Client-Side Rendering is a common data fetching method using useEffect. It will fetch the data from the API every single page request on the client-side (after the page is rendered, then the function will run).
- SSR - Server-Side Rendering will run a special function to fetch data from the API with every page request on the server-side (before the page is loaded, that special function will run first, creating a delay, then after that, it will serve the page).
- SSG - Static Site Generation will run a special function to fetch data once when that page builds.
- ISR – Incremental Static Regeneration offers a new method. Shortly put, it is a combination of SSG, and SSR, where it served statically, but at a certain time and certain condition, that page will rebuild and fetch the data from the API again.
Don't worry if you don't understand any of the concepts. I will explain a little bit further shortly.
CSR (Client-Side Rendering)
This is a basic example of how you can use Client-Side Rendering. I'm using the well known useEffect
method from React.
const ClientSide = () => {
const [data, setData] = useState(null);
const [isLoading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetch('api/hello')
.then((res) => res.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, []);
if (isLoading) return <p>Loading...</p>;
if (!data) return <p>No profile data</p>;
return (
<div>
<h1>My name is {data.name}</h1>
</div>
);
};
export default ClientSide;
You can see how it works on Stackblitz.
We can highlight 2 things here:
- The
useEffect
method to make the retrieve of thename
every time the page loads. - A loading indicator, this is used to wait for the fetching data, because the data is fetched after the page is rendered.
SSR (Server-Side Rendering)
Just to keep in mind, when you are using Server-Side rendering, and using the method getServerSideProps()
, Next.js will pre-render this page on each request using the data returned by getServerSideProps.
import styles from '../styles/Home.module.css';
const ServerSide = ({ joke }) => {
return (
<div className={styles.container}>
<span className={styles.description}>Today's joke:</span>
<h1 className={styles.title}>{joke}</h1>
</div>
);
};
// This gets called on every request
export async function getServerSideProps() {
const url = 'https://icanhazdadjoke.com/';
const res = await fetch(url, {
headers: {
Accept: 'application/json',
},
});
const data = await res.json();
return {
props: {
joke: data.joke,
},
};
}
export default ServerSide;
You can see how it works: Stackblitz
We had 3 highlights here:
- Method
getServerSideProps()
, is a function indicating that a page is using Server-Side Rendering. - We had a delay before render, and NO loading indicator. The data is fetched before the page is rendered, so that's why we can see a little delay.
- Data is fetched on every request, that's why every time we reload the page, is showing a different dad joke.
SSG (Static Site Generator)
If we take a look at the code below, we will see that it is pretty similar to the SSR code, but the difference here is the getStaticProps
method. This method will only fetch when the app is building.
import styles from '../styles/Home.module.css';
const StaticSite = ({ joke }) => {
console.log(joke);
return (
<div className={styles.container}>
<span className={styles.description}>Today's joke:</span>
<h1 className={styles.title}>{joke}</h1>
</div>
);
};
// This gets called on every request
export async function getStaticProps() {
console.log('getStaticProps');
const url = 'https://icanhazdadjoke.com/';
const res = await fetch(url, {
headers: {
Accept: 'application/json',
},
});
const data = await res.json();
console.log(data);
return {
props: {
joke: data.joke,
},
};
}
export default StaticSite;
The highlights here are:
getStaticProps
is a method indicating that the page is using Static Site Generation.- Data will be fetched only when you run
yarn build
. The API will be hit only when the app is building. - Data will NOT change because there is no further fetch.
You can see how it works: Stackblitz
ISR (Incremental Static Regeneration)
This strategy works pretty simmilar like SSG, but here we need to add a revalidate
prop to our main getStaticProps function.
import styles from '../styles/Home.module.css';
const IncrementalStatic = ({ joke }) => {
console.log(joke);
return (
<div className={styles.container}>
<span className={styles.description}>Today's joke:</span>
<h1 className={styles.title}>{joke}</h1>
</div>
);
};
export async function getStaticProps() {
console.log('getStaticProps');
const url = 'https://icanhazdadjoke.com/';
const res = await fetch(url, {
headers: {
Accept: 'application/json',
},
});
const data = await res.json();
console.log(data);
return {
props: {
joke: data.joke,
revalidate: 20,
},
};
}
export default IncrementalStatic;
There are a few keys to highlight here:
-
When you set the
revalidate
prop to certain amount of time (in our example we set it to 20), reloading doesn't trigger changes. The page will remain in a cooldown state. -
Is the page rebuilt every 20 seconds then?
No. When the cooldown state is off, if no one visits the page, it will not rebuild even after the 20s pass. But the first person who enters the page when the cooldown state is off will trigger a rebuild. However, that person will not see those changes. But the changes will be applied to the next full reload.
You can see how it works: Stackblitz
Conclusion
Understand how these abbreviations work, and how we can use it in a Next.js app will help us develop more robust solutions, and use Next.js' full potential. I know these terms can sound overwhelming and difficult to understand, but with a little bit of practicing, we can see in action in a few steps.
In future blog posts, we will see the best approach to identify and choose between them.