We all love Next.JS for its ability to render static pages for our dynamic content. Previously, when new content was added, one had to completely rebuild the site, but no longer!
Introducing: Incremental Static Regeneration, or ISR. ISR allows only a specific page to regenerate in the background when changes are detected. There are two ways to implement this feature: automatic regeneration and on-demand regeneration. I will cover both methods.
Automatic Regeneration
Automatic regeneration is handled by the Next functions getStaticProps()
and getStaticPaths()
. To implement ISR, we only have to worry about two lines of code:
/* [slug].js */
export async function getStaticProps({ params }) {
const res = await getPost(params.slug)
return {
props: {
post: res[0].fields
},
revalidate: 10 // Revalidate max 10 seconds
}
}
export async function getStaticPaths() {
const slugs = await getPostSlugs();
const paths = slugs.map((slug) => ({
params: { slug: slug },
}));
return {
paths,
fallback: 'blocking' // SSR page and then cache
};
}
I've added the revalidate: 10
directive to getStaticProps()
. This means that stale content will only be displayed for a maximum of 10 seconds, and then is revalidated and rebuilt in the background. The next refresh after this time expires will display the current content.
In getStaticPaths()
, I've set fallback
to blocking
. What this does is, if the current path does not exist, it is Server-Side Rendered. Subsequent renders will be served from the cache from then on.
That's it! It's that simple.
On-Demand ISR
You may want to consider on-demand ISR, especially if you want new content to be live immediately. Let's say you have an eCommerce store and you want to change the price of a product. We'll create an API path that will allow us to regenerate a path or list of paths on demand. We'll use a secure API key to prevent abuse.
Here's the code for my API:
/* revalidate.js */
export default async function handler(req, res) {
// Get our API key from 'authorization' header
const bearer = req.headers['authorization'];
if (!bearer) return res.status(401).json({ message: 'Unauthorized' })
const key = bearer.split(" ").pop();
// Compare given key to secret key
if (key !== process.env.REVAL_SECRET) {
return res.status(401).json({ message: 'Unauthorized' })
}
// Get paths array from POST request
const paths = req.body.paths ?? null;
if (!paths || typeof paths !== 'array') return res.status(400).json({ message: 'Bad Request: No paths specified' })
try {
paths.forEach(async (p) => {
await res.unstable_revalidate(p)
})
return res.json({ revalidated: true })
} catch (err) {
// Catch error and serve 500
return res.status(500).send('Error revalidating')
}
}
Now we can test this by sending a request to the API:
/* Revalidate Request Example */
const axios = require('axios');
const postData = {
paths: [
'/blog',
'/blog/post/blog-post-one',
'/blog/post/blog-post-two'
]
}
const res = await axios({
headers: {
'Authorization': `Bearer ${process.env.REVAL_SECRET}`
},
method: 'POST',
url: '/api/revalidate',
data: postData
}).then((res) => {
return res
}).catch((e) => {
console.log(e);
});
That's all there is to it. This new(ish) feature has completely solidified my committment to Next.JS. I hope you feel the same way!
For more great information, please Visit Our Blog.