如何在 Next.js 13 应用程序目录中缓存从 firebase firestore 获取的数据

问题描述 投票:0回答:1

当我们从 firebase 获取数据时,我想在下一个 js 服务器端页面上缓存数据。我已经知道我们可以使用

fetch
api

缓存默认数据

https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#fetching-data-on-the-server-with-fetch

但我想在没有这个的情况下缓存数据,因为我没有任何 API

基本上在我的下一个 js 应用程序中,我有一个名为“[用户名]”的动态路由

enter image description here

因此示例网址将是“https://prozo.me/@hardikdesai”,我使用此函数通过用户名获取该用户的数据

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 }
}

所以,我希望我获取的数据能够缓存 60 秒。并且当时不发出任何 firebase 数据库请求

页面.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} />
}
firebase google-cloud-firestore next.js caching next.js13
1个回答
0
投票

Next.js 提供了一个体验式

cache
函数,旨在写入 Next.js 数据缓存,其功能与扩展
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 */
  }
)

其功能与

fetch
API 中的缓存类似,它允许设置重新验证选项来定义缓存数据何时应过时或调用
revalidateTag("getUserDetailsByUsername")
立即使缓存失效。

它接受 3 个参数:

  • 要缓存的获取函数
  • 一系列关键部件确保组合时的全局唯一性。
  • 一个选项对象包含:
    • tags
      :可与
      revalidateTag
      一起使用的键数组。
    • revalidate
      :缓存应重新验证的时间间隔(以秒为单位)。

在文档中阅读更多内容:https://nextjs.org/docs/app/api-reference/functions/unstable_cache


高级:

目前,

revalidateTag
存在局限性,不支持单个用户重新验证,例如,
revalidateTag("getUserDetailsByUsername", "JohnDoe")
不可行。调用
revalidateTag("getUserDetailsByUsername")
会使所有缓存的用户失效。解决方法包括稍微重组:

const getUserDetailsByUsername = async (username) => {
  const cachedFn = cache(
    getUserDetailsByUsernameImpl,
    [`getUserDetailsByUsername-${username}`],
    {
      tags: ["getUserDetailsByUsername", `getUserDetailsByUsername-${username}`],
      revalidate: 60 * 60 * 24
    }
  )

  return cachedFn(username); 
}

此方法将用户名包含在缓存标记中,以便在必要时重新验证特定用户:

revalidateTag(`getUserDetailsByUsername-${username}`)
© www.soinside.com 2019 - 2024. All rights reserved.