使用onSnapshot与RTK Query获取Firebase实时数据报错解决
问题原因
- 直接触发TS报错的原因:
onSnapshot是绑定实时监听的非阻塞API,传入的回调函数不会在当前代码执行流里立刻运行。你声明tweetsArr后没有设置初始值,代码执行到return {data:tweetsArr}时,onSnapshot的回调还没触发,变量根本没被赋值,因此抛出「变量在赋值前被使用」的错误。 - 实时数据不生效的核心原因:RTK Query普通
queryFn默认是一次性返回结果的执行逻辑,就算你加延时等第一次快照拿到数据返回,后续Firebase推送的内容更新也不会同步到RTK Query缓存里,完全实现不了实时更新的效果。
正确修改方式
对接Firebase实时快照这类持续推送的数据源,需要用RTK Query提供的缓存更新能力:在queryFn中绑定快照监听,每次收到新的快照数据时主动更新缓存,同时返回解绑监听的方法,避免组件卸载后出现内存泄漏。
修改后的apiSlice.js代码
import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; import { collection, onSnapshot } from 'firebase/firestore'; import { db } from './你的firebase配置文件路径'; // 根据实际业务字段调整Post类型定义 interface Post { id: string; content: string; // 其余业务字段... } export const apiSlice = createApi({ reducerPath:'api/apiSlice', baseQuery: fakeBaseQuery(), endpoints: builder => ({ getPosts: builder.query<Post[], void>({ async queryFn(_, { updateCachedData }) { try { // 绑定Firebase实时监听 const unsubscribe = onSnapshot( collection(db,'tweets'), (querySnapshot) => { const tweetsArr: Post[] = querySnapshot.docs.map((doc) => { // 携带文档id,后续列表渲染无需用index作为key return { id: doc.id, ...doc.data() } as Post; }); // 每次收到快照更新,同步更新RTK Query缓存 updateCachedData(() => tweetsArr); } ); // 初始返回空数组,后续数据更新通过updateCachedData主动推送 return { data: [], unsubscribe }; } catch(err: any) { return { error: err }; } } }), // 原有addPost mutation逻辑保持不变即可 }) }); export const { useGetPostsQuery, useAddPostMutation } = apiSlice;
组件侧优化
原逻辑用数组下标作为列表key容易出现渲染异常,建议用Firebase返回的文档id作为key,调整后的列表渲染逻辑:
const PostsList = () => { const {data:posts, isLoading, error, isError} = useGetPostsQuery(); let content; if(isLoading){ content = <LoadingSpinner/>; } else if(isError){ const err = error as {message?: string}; content = <p>{err?.message}</p>; } else if(posts){ // 用post.id作为key,避免列表更新时出现渲染bug content = posts.map((post) => ( <Post key={post.id} {...post}/> )); } return ( <section className="posts-list"> {content} </section> ) }
注意事项
- 不需要手动调用
unsubscribe方法,RTK Query会在组件不再使用该查询(比如组件卸载、查询参数变化触发新请求)时自动执行解绑,清除Firebase监听。 - 如果需要处理快照监听的运行错误,可以在
onSnapshot的第二个参数位置传入错误回调,把错误状态同步给组件。
内容的提问来源于stack exchange,提问作者H.b
相关产品推荐
相关产品推荐

