Next.js 14使用unstable_cache缓存Firestore遇incrementalCache missing错误求代码
Next.js 14 用
unstable_cache缓存Firestore数据时"incrementalCache missing"错误解决办法 为啥会报错?
unstable_cache是Next.js仅服务端可用的缓存API,只能在Server Components、路由处理器、Server Actions这类服务端环境中调用。你原来的代码是在客户端组件的useEffect里直接使用,客户端环境根本不存在incrementalCache实例,自然就触发了这个错误。
另外,你用的onSnapshot是Firestore的实时监听API,适合客户端实时同步数据,但要结合缓存得分场景处理。
方案一:服务端组件+unstable_cache缓存静态数据(无需实时更新)
如果不需要实时同步Firestore数据,只是想缓存查询结果,直接在Server Components中实现:
// app/users/[userId]/rules/page.tsx(默认就是Server Component) import { unstable_cache } from 'next/cache' import { collection, getDocs } from 'firebase/firestore' import { db } from '@/lib/firebase' // 包装带缓存的Firestore查询函数 const getCachedUserRules = unstable_cache( async (userId: string) => { const snapshot = await getDocs(collection(db, 'users', userId, 'rules')) return snapshot.docs.map(doc => doc.data() as RulesProps) }, ['user-rules'], // 缓存标识键,区分不同缓存条目 { revalidate: 3600, // 1小时后自动刷新缓存 tags: [`user-${userId}-rules`] // 缓存标签,用于后续主动失效缓存 } ) export default async function RulesPage({ params }: { params: { userId: string } }) { const rules = await getCachedUserRules(params.userId) return ( <div> {rules.map(rule => ( <div key={rule.id}>{rule.name}</div> ))} </div> ) }
方案二:服务端缓存初始数据+客户端实时监听(兼顾缓存与实时)
如果想初始加载用缓存数据,之后保持实时更新,就把服务端组件和客户端组件结合起来:
1. 服务端组件提供初始缓存数据
// app/users/[userId]/rules/page.tsx(Server Component) import { unstable_cache } from 'next/cache' import { collection, getDocs } from 'firebase/firestore' import { db } from '@/lib/firebase' import RulesClient from './RulesClient' const getCachedUserRules = unstable_cache( async (userId: string) => { const snapshot = await getDocs(collection(db, 'users', userId, 'rules')) return snapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as RulesProps)) }, ['user-rules'], { revalidate: 3600, tags: [`user-${userId}-rules`] } ) export default async function RulesPage({ params }: { params: { userId: string } }) { const initialRules = await getCachedUserRules(params.userId) // 将初始缓存数据传给客户端组件 return <RulesClient initialRules={initialRules} userId={params.userId} /> }
2. 客户端组件实现实时监听
// app/users/[userId]/rules/RulesClient.tsx(标记为客户端组件) 'use client' import { useState, useEffect } from 'react' import { collection, onSnapshot } from 'firebase/firestore' import { db } from '@/lib/firebase' type Props = { initialRules: RulesProps[] userId: string } export default function RulesClient({ initialRules, userId }: Props) { const [rules, setRules] = useState<RulesProps[]>(initialRules) const [loading, setLoading] = useState(false) useEffect(() => { setLoading(true) const unsubscribe = onSnapshot( collection(db, 'users', userId, 'rules'), (snapshot) => { const updatedRules = snapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as RulesProps)) setRules(updatedRules) setLoading(false) } ) // 组件卸载时取消监听 return () => unsubscribe() }, [userId]) if (loading) return <div>加载中...</div> return ( <div> {rules.map(rule => ( <div key={rule.id}>{rule.name}</div> ))} </div> ) }
方案三:Firestore数据变化时主动失效缓存
如果想在Firestore数据更新时立刻让缓存失效,可以用Firebase云函数触发Next.js的Server Action:
1. 定义Server Action用于失效缓存
// app/actions.ts 'use server' import { revalidateTag } from 'next/cache' export async function revalidateUserRules(userId: string) { // 根据标签清除对应缓存 revalidateTag(`user-${userId}-rules`) }
2. 云函数监听Firestore变化并调用Action
// functions/index.js const functions = require('firebase-functions') const axios = require('axios') exports.onRuleUpdated = functions.firestore .document('users/{userId}/rules/{ruleId}') .onWrite(async (change, context) => { const userId = context.params.userId // 调用你的Next.js服务端Action,替换为自己的域名 await axios.post(`${process.env.NEXT_APP_URL}/api/revalidate`, { userId }) })
关键注意事项
unstable_cache是实验性API,生产环境使用前请确认Next.js版本兼容性- 缓存键和标签要唯一,避免不同用户的数据缓存冲突
- 客户端组件绝对不能直接调用
unstable_cache,必须通过服务端组件或Server Actions间接使用
内容的提问来源于stack exchange,提问作者Lucas Carvalho
相关产品推荐
相关产品推荐

