react-firebase-hooks中useCollectionOnce无限加载问题
问题产生原因
useCollectionOnce、useDocumentOnce出现永久加载的核心原因是传入hook的查询对象、配置对象引用不稳定:
- 你当前的写法里,每次组件重新渲染都会重新执行
query()、collection()、配置对象字面量的创建逻辑,生成全新的引用值传给hook - 一次性拉取类的hook内部没有做实时监听类hook(
useCollection/useDocument)自带的查询引用去重逻辑,每次接收到新的引用都会判定为新请求,重置加载状态重新发起拉取,形成死循环,最终表现为isLoading永远为true - 触发热重载时功能恢复正常,是因为热重载会临时保留组件上一次渲染的hook状态,不会重复触发初始化拉取逻辑,第一次请求返回的结果可以被正常捕获,加载状态就能正常结束。
useDocumentOnce出现完全相同问题的根因和上述逻辑一致,套用相同的引用稳定方案即可修复。
修复方案
方案1:用
useMemo缓存查询实例、配置对象,保证非必要场景下引用稳定
参考实现代码:import { useMemo, useEffect } from 'react'; import { getFirestore, collection, query, orderBy, limit } from 'firebase/firestore'; import { useCollectionOnce } from 'react-firebase-hooks/firestore'; function YourComponent() { // 缓存firestore实例 const db = useMemo(() => getFirestore(), []); // 缓存查询构造逻辑,依赖变化时才重新生成 const dataQuery = useMemo(() => { return query( collection(db, 'examplePath'), orderBy('test'), limit(2) ) }, [db]); // 缓存配置对象 const queryOptions = useMemo(() => ({ getOptions: { source: 'server' } }), []); const [data, isLoading, isError] = useCollectionOnce(dataQuery, queryOptions); useEffect(() => { console.debug(isLoading) }, [isLoading]) // 其余组件逻辑 }如果查询条件依赖组件的state、props,把对应变量加到
useMemo的依赖数组里即可,既可以保证条件变化时触发新查询,也能避免无关渲染导致的重复请求。方案2:固定查询条件的场景下,把查询、配置定义在组件外部作为模块常量
如果你的查询筛选规则不会随组件状态变化,可以直接把query和配置移到组件外,整个模块生命周期内引用都不会变化,从根源避免重复创建引用的问题:import { useEffect } from 'react'; import { getFirestore, collection, query, orderBy, limit } from 'firebase/firestore'; import { useCollectionOnce } from 'react-firebase-hooks/firestore'; // 组件外定义常量 const db = getFirestore(); const FIXED_DATA_QUERY = query( collection(db, 'examplePath'), orderBy('test'), limit(2) ); const FIXED_QUERY_OPTIONS = { getOptions: { source: 'server' } }; function YourComponent() { const [data, isLoading, isError] = useCollectionOnce(FIXED_DATA_QUERY, FIXED_QUERY_OPTIONS); useEffect(() => { console.debug(isLoading) }, [isLoading]) // 其余组件逻辑 }方案3:版本兼容排查
部分旧版本的react-firebase-hooks存在一次性拉取hook状态更新丢失的已知问题,如果上述两种方案都不生效,可以把依赖升级到对应firebase SDK兼容的最新稳定版本,排除版本bug影响。
内容的提问来源于stack exchange,提问作者Samuele1818
相关产品推荐
相关产品推荐

