You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React搭配Firebase Firestore开发时数据仅在第二/三次渲染才成功获取

问题根源

你的代码问题出在两个useEffect的依赖项设置错误、执行时序不匹配,和加载态判断逻辑错误:

  • 两个useEffect都只在组件首次挂载时触发,属于并行执行,第二个查询books的useEffect运行时,第一个请求用户数据的接口还没返回,userBookTitles还是初始的空数组,所以第一次查询无结果
  • 你在第二个useEffect里直接把loading设为false,此时用户数据和书籍数据都还没加载完成,所以页面提前渲染了空数据
  • 等第一个接口拿到用户数据更新userBookTitles后,第二个useEffect没有监听这个变量,不会重新触发查询,所以要多次渲染才能拿到数据

修复方案

  1. 调整第二个useEffect的依赖项为userBookTitles,只有当userBookTitles有值时才触发书籍查询
  2. 把加载态关闭的时机移到书籍数据查询完成后
  3. 如果不需要书籍数据实时更新,可以不用onSnapshot,改用一次性的get方法即可;如果要用onSnapshot,需要添加清理函数取消监听,避免内存泄漏

修改后参考代码

import 'firebase/firestore'
import { useState, useEffect } from 'react'
import { booksRef} from '../../App';

const ProfileScreen = ({ navigation }) => {
  const currentUserUID = firebase.auth().currentUser.uid;
  const [firstName, setFirstName] = useState('');
  const [userBookTitles, setUserBookTitles] = useState([]);
  const [userBooks, setUserBooks] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function getUserInfo(){
      let doc = await firebase
      .firestore()
      .collection('users')
      .doc(currentUserUID)
      .get();
      
      if (!doc.exists){
        Alert.alert('No user data found!')
        setLoading(false)
      } else {
        let dataObj = doc.data();
        setFirstName(dataObj.firstName)
        setUserBookTitles(dataObj.books || [])
      }
    }
    getUserInfo();
  }, [currentUserUID])

  useEffect(() => {
    // 只有用户的书籍列表有值时才查询书籍集合
    if(userBookTitles.length === 0) return

    // 用onSnapshot的情况,添加清理函数
    const unsubscribe = booksRef.where("title", "in", userBookTitles).onSnapshot(snapshot => {
      setUserBooks(snapshot.docs.map((doc) => ({id: doc.id, ...doc.data()})))
      setLoading(false) // 书籍数据拿到后再关加载
    })
    
    // 组件卸载时取消监听
    return () => unsubscribe()

    // 不需要实时更新的话可以用get方法:
    /*
    const getUserBooks = async () => {
      const snapshot = await booksRef.where("title", "in", userBookTitles).get()
      setUserBooks(snapshot.docs.map(doc => ({id: doc.id, ...doc.data()})))
      setLoading(false)
    }
    getUserBooks()
    */
  }, [userBookTitles])


  if (!loading) {
    return (
        <View style={styles.container}>
          <Text> Hi {firstName} </Text>
          <TouchableOpacity onPress={handlePress}>
            <Text> Log out </Text>
          </TouchableOpacity>
          <Row
                  books={userBooks}
          />
        </View>
    );  
  } else { 
    return (
      <View style={styles.container}>
        <Text> 加载中 </Text>
      </View>
  );
  }
};

内容的提问来源于stack exchange,提问作者Dybton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 06:27:02