Reputation: 218
I want to cache data on next js server side page, when we fetch data from firebase. i already know that we can cache default data using fetch
api
but i want to cache data without this, as i don't have any APIs
basically in my next js app i have one dynamic route called "[username]"
So the example url will be "https://prozo.me/@hardikdesai", and i am fetching that user's data by username with this function
export const getUserDetailsByUsername = async (username: string): Promise<{ userDetails: any; message?: string }> => {
const q = DB.collection('users').where('username', '==', username)
const querySnapshot = await q.get()
if (querySnapshot.empty) {
return { userDetails: null, message: 'User not found' }
}
const userDetails = querySnapshot.docs[0].data()
return { userDetails }
}
so, i want that my fetched data would ne cached for 60 seconds. and not make any firebase db request for that time
page.tsx
// sections
import { Metadata } from 'next'
import { getUserDetailsByUsername } from 'src/queries/user'
import { ProfileView } from 'src/sections/username/view'
// ----------------------------------------------------------------------
type Props = {
params: { username: string }
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
return {
title: `${decodeURIComponent(params?.username)} | Prozo`,
}
}
export default async function ProfilePage({ params }: { params: { username: string } }) {
const { userDetails } = await getUserDetailsByUsername(params?.username?.slice(3))
return <ProfileView userDetails={userDetails} />
}
Upvotes: 0
Views: 476
Reputation: 4926
Next.js offers an experiential cache
function designed to write to the Next.js Data Cache, functioning similarly to the extended fetch
API.
import { unstable_cache as cache } from "next/cache";
const getUserDetailsByUsernameImpl = async (username: string): Promise<{ userDetails: any; message?: string }> => {
const q = DB.collection('users').where('username', '==', username)
const querySnapshot = await q.get()
if (querySnapshot.empty) {
return { userDetails: null, message: 'User not found' }
}
const userDetails = querySnapshot.docs[0].data()
return { userDetails }
}
const getUserDetailsByUsername = cache(
/* fetch function */ getUserDetailsByUsernameImpl,
/* unique key */ ["getUserDetailsByUsername"],
/* options */ {
tags: ["getUserDetailsByUsername"],
revalidate: 60 * 60 * 24 /* same as fetch.revalidate */
}
)
Functioning similar to caching in the fetch
API, it allows setting a revalidate option to define when cached data should become stale or invoking revalidateTag("getUserDetailsByUsername")
to instantly invalidate the cache.
It accepts 3 parameters:
tags
: An array of keys usable with revalidateTag
.revalidate
: The interval in seconds after which the cache should be revalidated.Read more in the documentation: https://nextjs.org/docs/app/api-reference/functions/unstable_cache
Currently, there's a limitation with revalidateTag
where individual user revalidation isn't supported, for instance, revalidateTag("getUserDetailsByUsername", "JohnDoe")
isn't feasible. Invoking revalidateTag("getUserDetailsByUsername")
invalidates all cached users. A workaround involves a slight restructuring:
const getUserDetailsByUsername = async (username) => {
const cachedFn = cache(
getUserDetailsByUsernameImpl,
[`getUserDetailsByUsername-${username}`],
{
tags: ["getUserDetailsByUsername", `getUserDetailsByUsername-${username}`],
revalidate: 60 * 60 * 24
}
)
return cachedFn(username);
}
This approach includes the username in the cache tag, enabling the revalidation of a specific user when necessary:
revalidateTag(`getUserDetailsByUsername-${username}`)
Upvotes: 2