如何手动结合TanStack Query与Firebase Firestore实现缓存功能
手动用TanStack Query缓存Firestore数据的实现方案
1. 基础初始化
先确保项目已安装firebase和@tanstack/react-query依赖。
首先初始化Firebase实例(根据你的项目配置调整):
// firebase.js import { initializeApp } from "firebase/app"; import { getFirestore } from "firebase/firestore"; const firebaseConfig = { // 你的Firebase配置信息 }; const app = initializeApp(firebaseConfig); export const db = getFirestore(app);
在项目入口配置TanStack Query的QueryClient和QueryClientProvider:
// App.jsx import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { db } from "./firebase"; const queryClient = new QueryClient({ defaultOptions: { queries: { // 默认缓存有效期(单位:毫秒) staleTime: 5 * 60 * 1000, // 5分钟 // 缓存数据保留时间,超出后自动清理 cacheTime: 10 * 60 * 1000, // 10分钟 // 关闭自动后台刷新(仅需缓存时启用) refetchOnWindowFocus: false, refetchOnMount: false, }, }, }); function App() { return ( <QueryClientProvider client={queryClient}> {/* 你的应用组件 */} </QueryClientProvider> ); } export default App;
2. 封装Firestore查询并启用缓存
创建自定义Hook,用useQuery封装Firestore数据获取逻辑,核心是指定唯一缓存键和数据获取函数。
示例1:获取单个文档
// hooks/useFirestoreDocument.js import { useQuery } from "@tanstack/react-query"; import { doc, getDoc } from "firebase/firestore"; import { db } from "../firebase"; export function useFirestoreDocument(collectionName, docId) { return useQuery({ // 唯一缓存键,用于标识缓存数据 queryKey: ["firestore", collectionName, docId], // 数据获取函数,返回Promise queryFn: async () => { const docRef = doc(db, collectionName, docId); const docSnap = await getDoc(docRef); if (!docSnap.exists()) { throw new Error("文档不存在"); } // 返回带ID的文档数据 return { id: docSnap.id, ...docSnap.data() }; }, // 可选:单独设置该查询的缓存规则,覆盖全局默认 staleTime: 10 * 60 * 1000, // 10分钟 }); }
组件中使用:
// components/Post.jsx import { useFirestoreDocument } from "../hooks/useFirestoreDocument"; function Post({ postId }) { const { data: post, isLoading, error } = useFirestoreDocument("posts", postId); if (isLoading) return <div>加载中...</div>; if (error) return <div>错误:{error.message}</div>; return ( <div> <h1>{post.title}</h1> <p>{post.content}</p> </div> ); }
示例2:获取集合列表
// hooks/useFirestoreCollection.js import { useQuery } from "@tanstack/react-query"; import { collection, getDocs } from "firebase/firestore"; import { db } from "../firebase"; export function useFirestoreCollection(collectionName) { return useQuery({ queryKey: ["firestore", collectionName], queryFn: async () => { const colRef = collection(db, collectionName); const querySnapshot = await getDocs(colRef); // 将集合转换为带ID的数组 return querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); }, }); }
3. 手动控制缓存
通过queryClient提供的方法主动管理缓存:
3.1 手动更新缓存数据
修改文档后直接更新缓存,避免重复请求:
import { useQueryClient } from "@tanstack/react-query"; import { doc, updateDoc } from "firebase/firestore"; import { db } from "../firebase"; function EditPost({ postId }) { const queryClient = useQueryClient(); const handleUpdate = async (newData) => { const docRef = doc(db, "posts", postId); await updateDoc(docRef, newData); // 更新缓存中的对应数据 queryClient.setQueryData(["firestore", "posts", postId], (oldData) => { return { ...oldData, ...newData }; }); }; return <button onClick={() => handleUpdate({ title: "新标题" })}>更新</button>; }
3.2 使缓存失效(触发重新请求)
强制刷新数据时,让对应缓存键失效:
// 失效单个文档缓存 queryClient.invalidateQueries({ queryKey: ["firestore", "posts", postId] }); // 失效整个集合缓存 queryClient.invalidateQueries({ queryKey: ["firestore", "posts"] });
3.3 手动移除缓存
不再需要某条缓存数据时直接移除:
queryClient.removeQueries({ queryKey: ["firestore", "posts", postId] });
4. 关键注意事项
- 缓存键唯一性:
queryKey必须唯一标识数据(如集合名+文档ID),确保TanStack Query能正确匹配缓存。 - 错误处理:在
queryFn中抛出错误,useQuery会自动捕获并设置error状态,便于组件处理。 - 缓存策略调整:根据业务需求修改
staleTime和cacheTime,若需数据始终新鲜,可将staleTime设为0(仍会用缓存展示直到新数据返回)。 - 避免重复请求:相同
queryKey的查询在缓存有效期内,TanStack Query会直接返回缓存数据,不会重复调用Firestore接口。
内容的提问来源于stack exchange,提问作者Mamta
相关产品推荐
相关产品推荐

