How to Revalidate Server Components in Next.js 13th?

February 20th, 2024
Share:
How to Revalidate Server Components in Next.js 13th?

When you retrieve data from the Server Components, Next.js automatically caches the returned values on the server. This means that data won`t be fetched again on every request, which helps optimize the initial page loading time and improve the performance. However, there may be instances where you need to revalidate the data to ensure that up-to-date information is being displayed.

Methods for Re-Fetching Data

Next.js provides two methods for data re-fetching: time-based and on-demand revalidation.

Time-based revalidation automatically updates data after a specific time interval.

fetch(url, { next: { revalidate: 3000 } })

On-demand revalidation allows data to be re-fetched after a specific action. Data can be updated by path, using the revalidatePath method, or by cache tag, using the revalidateTag method. If you have a single API request that contains all the dynamic page information, updating data by path can be helpful. However, if multiple calls are on one page, each responsible for its own data set, it`s better to update data by tag. This method ensures that only the required data is updated, making the process more efficient.

Let`s consider an example close to the one we recently worked on.

Suppose we have a dynamic service page with different sections:

  • Section 1: The primary service information, such as service name, description, price, etc;
  • Section 2: List of additional service options;
  • Section 3: Information about the service provider;
  • Section 4: Reviews;

Each section has its own API.

Except for service reviews, all APIs can be requested and cached on the server. Reviews are dynamic and should be fetched on the client side (in the useEffect).

Let`s create a Service server component and fetch the required data.

// API request common function
const fetchData = async (url, data, options) => {
const response = await fetch(url, {
...(options || {}),
method: 'POST',
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return await response.json();
}
// Service.jsx(.tsx) server component
import React from 'react';
const getService = async (id) => {
const service = await fetchData('serviceInfoURL', { id });
if (!service?.id) {
return null;
}
const serviceData = await Promise.all([
fetchData('serviceOptionsURL', { serviceID: service?.id }),
fetchData('serviceProviderURL', { userID: service?.userID }),
]);
const [options, provider] = serviceData || [];
return { service, options, provider }
};
const Service = async ({ params }) => {
const { id } = params;
const response = await getService(id);
if (!response) {
notFound();
}
const { options, service, provider } = response || {};
return <div>... {service?.name}</div>;
};

In the code above, the Service is an asynchronous React server component that fetches the service information. Once the promise is resolved, the server caches data and subsequent page requests won`t re-fetch it again. This caching ensures that the data remains consistent, even if the service provider updates the service name or other fields.

To revalidate service data after updates, we can use the revalidateTag function to re-fetch only service-related APIs and not all of them. Provider information, for example, always remains the same and does not need revalidation.

Revalidating the Service Information

First, we need to add the revalidation tag to the API calls: service and options info.

// Add the service-${id} tag: { next: { tags: [`service-${id}`] }}
const getService = async (id) => {
const service = await fetchData('serviceInfoURL', { id }, { next: { tags: [`service-${id}`] }});
const serviceData = await Promise.all([
fetchData('serviceOptionsURL', { serviceID: service?.id },{ next: { tags: [`service-${id}`] }}),
]);
};

Next, create an actions file at the root of the app folder and add the following code.

// actions.js(.ts)
'use server';
import { revalidateTag } from 'next/cache';
export async function clearServiceCache(id) {
revalidateTag(`service-${id}`);
}

Then, call the clearServiceCache function on the Service Edit form after the successful submission.

// ServiceEditForm.jsx(.tsx) component
const ServiceEditForm = (service) => {
const { push } = useRouter();
const handleSubmit = (values) => {
//on onSuccess
clearServiceCache(service?.id).then(() => {
push(`services/${service?.id}`); //Redirect to the service page
});
};
return (...);
};

Once the cache reset is successful, the user will be redirected to the updated service page. Only service-related APIs will be re-fetched, while the provider information will be retrieved from the cache.

Passing the service ID to the revalidatieTag function allows data to be revalidated only for a specific service.

Revalidating the Provider Information

In the actions file, you can create any functions you need. For example, we can create another function called clearProviderCache with a different tag to reset the cache of the provider info.

// Add another function to the actions.js(.ts) file
export async function clearProviderCache(id) {
revalidateTag(`provider-${id}`);
}

Then, specify this tag in the provider fetch.

// Add the provider-${id} tag: { next: { tags: [`provider-${service?.userID}`] }}
fetchData('serviceProviderURL', { userID: service?.userID }, { next: { tags: [`provider-${service?.userID}`] }}),

After updating a provider`s information, the provider-related API will be re-fetched, and the rest of the service data will be retrieved from the cache.

Additionally, Next.js provides a method to fetch data on every request without caching it permanently.

fetch('https://...', { cache: 'no-store' })

Conclusion

This article explains how to revalidate data in Server Components in Next.js. If you have an alternative solution or ideas for improvement, please let us know. We will be glad to know!

We hope this article was helpful to you! Thanks for reading!

Subscribe icon

Subscribe to our Newsletter

Sign up with your email address to receive latest posts and updates