Firebase 9 + React Native 获取Cloud Firestore文档返回空数组问题
解决Firebase Firestore获取文档返回空数组的问题
使用Firebase 9.9.4版本,尝试从Firestore的values集合获取文档时始终得到空数组,以下是问题分析和修复方案:
问题分析
1. 初始实现的异步逻辑错误
在useLayoutEffect中,onSnapshot的回调是异步执行的,你在调用getValues()后立刻console.log(values),此时回调还未触发,因此values为空数组。同时没有用React状态存储数据,即使后续获取到数据,组件也不会重新渲染。
2. 自定义Hook的使用疏漏
你的useFireStore Hook逻辑本身正确,但组件中存在两个问题:
- 未将获取到的
docs关联到轮播组件的数据源carouselItems - 监听
docs的useEffect依赖为空,无法响应数据变化
修复方案
方案1:修正初始实现的异步逻辑
useLayoutEffect(() => { const q = query(collection(db, "values")); // 订阅数据变化 const unsubscribe = onSnapshot(q, (querySnapshot) => { // 遍历快照提取文档数据 const fetchedValues = querySnapshot.docs.map(doc => doc.data()); console.log(fetchedValues); // 此处可获取正确数据 // 用状态存储数据,触发组件更新 setValues(fetchedValues); }); // 组件卸载时取消订阅,避免内存泄漏 return () => unsubscribe(); }, [])
方案2:正确使用自定义Hook
// 完善自定义Hook(补充返回值) export const useFireStore = (mycollection : string) => { const [docs, setDocs] = useState<any>([]); useEffect(() => { const unsub = onSnapshot(collection(db, mycollection), (querySnapshot) => { const documents = querySnapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id // 建议携带文档ID,方便后续操作 })); setDocs(documents); }); return () => unsub(); }, [mycollection]) return docs; // 必须返回获取到的文档数组 } // 组件中正确使用Hook const ProfilesScreen: React.FC<Props> = ({ navigation, route}) => { const carouselRef = useRef() const [activeIndex, setActiveIndex] = useState<number>() const [carouselItems, setCarouselItems] = useState<any[]>([]); const windowHeight = useWindowDimensions().height; const windowWidth = useWindowDimensions().width; navigation.setOptions({ headerShown: false, }) // 调用自定义Hook获取数据 const docs = useFireStore('values') // 监听docs变化,更新轮播数据源 useEffect(() => { if(docs.length > 0) { console.log("docs", docs); setCarouselItems(docs); } }, [docs]); return( <SafeAreaView style={{flex: 1, backgroundColor:'white', paddingTop: 50, }}> <View style={{ flex: 1, flexDirection:'row', justifyContent: 'center', paddingTop:20}}> <Carousel layout={"default"} ref={carouselRef} data={carouselItems} // 使用更新后的数据源 sliderWidth={windowWidth} itemHeight={windowHeight} itemWidth={windowWidth} renderItem={ProfileScreenItem} onSnapToItem = {(index : number) => setActiveIndex(index)} /> </View> <SideBar carouselRef={carouselRef}/> </SafeAreaView> ) }
额外检查项
- Firestore安全规则:确认规则允许读取操作,开发阶段可临时设置为:
正式环境需设置严格权限。rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if request.auth != null; // 测试时可改为if true; } } } - 集合名称与文档存在性:确认Firestore控制台中
values集合名称(大小写敏感)正确,且集合内存在文档。
内容的提问来源于stack exchange,提问作者RandomDeveloper
相关产品推荐
相关产品推荐

