Skip to content

React Cache

Video Summary

Earlier, we learned about the Next metadata API, and saw how to use the generateMetadata function to dynamically calculate the page title from the route segments:

export async function generateMetadata({ params }) {
const { profileId } = await params;
const profile = await getProfileInfo(profileId);
return {
title: `${profile.name}’s profile`,
};
}

When the user visits /profiles/3, profileId will be equal to "3", and we use that parameter to fetch the user's profile info, so we can include the user's name in the document title.

This works well, but the trouble is that it often results in duplicate work being done. The component itself also needs to get the profile info!

export async function generateMetadata({ params }) {
const { profileId } = await params;
const profile = await getProfileInfo(profileId);
return {
title: `${profile.name}’s profile`,
};
}
async function ProfilePage({ params }) {
const { profileId } = await params;
const profile = await getProfileInfo(profileId);
// ✂️ Content removed for brevity
}

When a user visits this page, we'll wind up calling getProfileInfo twice. 😬

Now, this isn't as bad as I originally feared. The generateMetadata function runs in parallel to the component render. Both operations start at roughly the same time, and run simultaneously.

That said, is still bad. It doubles the amount of strain we're placing on our database. And it could negatively impact performance, since even the same database query can take a variable amount of time. Like the weakest link in the chain, the slower of the two queries slows down the entire request.

Fortunately, there is a solution to this problem: React.cache.

Here's what this looks like:

import React from 'react';
export const getProfileInfo = React.cache(
async (profileId) => {
await delay(Math.random() * 200 + 400);
return DATA[profileId];
}
);

React.cache allows us to memoize a function, so that the work won't be repeated when the function is called multiple times with the same parameters.

The best explanation I've heard for this is that it's like React.memo, but for regular functions instead of components.

React.cache is a per-request cache. It spins up when a request is made to a particular URL, and dissolves once the HTML is sent to the user. This means that it won't serve a cached value to other users, or to the same user if they refresh the page.

The cool thing about this API is that it doesn't require any changes to our React code. The only change we have to make is to wrap any functions that could be called multiple times.

You can learn more about the React.cache API in the React docs (opens in new tab).