使用useEffect与useSWRSubscription订阅Firestore实时数据有何差异?
问题
我正在通过查询和useEffect从Firebase的Cloud Firestore实时读取数据,代码如下:
import { useEffect } from 'react' useEffect(() => { const q = query( collection('some collection'), where('some condition') ) const unsubscribe = onSnapshot(q, qs => { const datas = []; qs.forEach((doc) => { datas.push(doc.data()); }); console.log(datas); }) return () => unsubscribe && unsubscribe() })
最近我了解到SWR——一款React数据获取Hook,其文档中展示了使用useSWRSubscription订阅Firestore数据源的示例,于是我将上述代码改写为:
import useSWRSubscription from 'swr/subscription' const { datas } = useSWRSubscription(queryParams ? queryParams : null, (_, { next }) => { const q = query( collection('some collection'), where('some condition') ) const unsubscribe = onSnapshot(q, qs => { next( null, qs.docs.map(doc => doc.data()) ) }, err => { return next(err) } ) return () => unsubscribe && unsubscribe() } console.log(datas)
请问这两段代码之间存在哪些差异?
两段代码的核心差异
1. 数据与组件状态的绑定逻辑
- 原生
useEffect版本:数据仅在回调内打印,没有和组件状态关联。如果要把数据用于渲染,必须手动声明useState并在回调里更新状态,否则组件无法感知数据变化。 useSWRSubscription版本:通过next函数把数据交给SWR管理,Hook直接返回datas,可以直接用于组件渲染,无需手动维护状态。
2. 错误处理能力
- 原生
useEffect版本:没有处理onSnapshot的错误回调,订阅出错时错误会直接抛出或被忽略,没有统一的错误捕获和处理逻辑。 useSWRSubscription版本:专门传入了错误回调,通过next(err)把错误传递给SWR,你可以从Hook返回值中获取error对象(比如const { datas, error } = useSWRSubscription(...)),方便统一处理错误状态。
3. 依赖变化时的订阅更新逻辑
- 原生
useEffect版本:如果查询条件(比如some condition里的变量)变化,必须手动把依赖项加入useEffect的第二个参数数组,否则不会重新创建查询和订阅,容易出现数据过时的问题。 useSWRSubscription版本:第一个参数是queryParams,当这个参数变化时,SWR会自动取消旧订阅并创建新订阅,无需手动管理依赖项,减少出错概率。
4. 数据转换的写法
- 原生
useEffect版本:通过forEach循环手动将文档数据push到数组,写法繁琐。 useSWRSubscription版本:使用qs.docs.map(doc => doc.data())直接转换为数组,写法更简洁高效。
5. 代码复用与扩展能力
- 原生
useEffect版本:订阅逻辑和组件强耦合,要复用必须自己封装自定义Hook。 useSWRSubscription版本:基于SWR生态,可以和SWR的缓存、重新验证、全局配置等功能集成,后续扩展更方便。
内容的提问来源于stack exchange,提问作者toom501
相关产品推荐
相关产品推荐

