当前位置: 首页 > 知识库问答 >
问题:

如何使用React从Firebase fiRecovery中的子集合中的所有文档中获取数据?

呼延化
2023-03-14

对于我的项目,我想从一个子集合中的所有文档中获取数据。并且这个子集合有多个文档。

为了澄清一下,这就是我的火力恢复的结构:我有一个事件集合,其中包含多个文档,doc.id是事件名称本身。每个事件文档都有几个字段和一个与会者子集合。在与会者子集合中,每个文档都包含有关与会者的详细信息。

我想浏览events集合中的所有文档,并从所有文档中获取关于与会者的数据。

我想在组件第一次渲染时显示这些数据。所以我调用了使用效果中的函数。这是我尝试过的:

const [attendeeInfo, setAttendeeInfo] = useState({});
    const [events, setEvents] = useState([]);

    const getEventsData = async () => {
        // first of all, we need the name of the user's org
        // fetch it from users collection by using the uid from auth
        const orgRef = doc(db, "users", auth["user"].uid);
        const orgSnap = await getDoc(orgRef);

        // now that we have the org name, use that to search events...
        // ...created by that org in events collection
        const eventsRef = collection(db, "events");
        const eventsQuery = query(eventsRef, where("createdBy", "==", orgSnap.data().orgName));
        const eventsQuerySnapshot = await getDocs(eventsQuery);
        let eventsInfo = [];

        eventsQuerySnapshot.forEach((doc) => {

            eventsInfo.push(doc.id);

        })

        setOrg(orgSnap.data().orgName);
        setEvents(eventsInfo);
    }

    const getAttendeesData = (events) => {
        console.log(events);
        let attendeeInformation = [];

        events.forEach(async (event) => {
            const attendeesRef = collection(db, "events", event, "attendees");
            const attendeesSnap = await getDocs(attendeesRef);

            attendeesSnap.forEach((doc) => {

                const isItMentor = doc.data().isMentor ? "Yes" : "No";
                const isItMentee = doc.data().isMentee ? "Yes" : "No";
                const attendeeData = {
                    name: doc.id,
                    mentor: isItMentor,
                    mentee: isItMentee,
                };

                attendeeInformation.push(attendeeData);
            })

        })

        // console.log(attendeeInformation);
        setAttendeeInfo(attendeeInformation);

    }


    useEffect(() => {

        getEventsData();
        // console.log(attendeeInfo);
        getAttendeesData(events);
    }, []);

然而,当我在我的attendeesData函数中控制台记录事件时,我得到一个空数组,这意味着事件状态变量还没有从前面的函数中更新。

有人能帮我解决这个吗?

共有1个答案

孙永嘉
2023-03-14

这是一个时间问题。在第一次渲染时,您开始获取事件列表,但在使用它们之前,您不会等待它们被检索。此外,由于只在装载时运行此代码,因此当<code>事件</code>最终更新时,<code>getAttendeesData</code>将不会与更新的数组一起调用。

useEffect(() => {
    getEventsData(); // <-- queues and starts "fetch event IDs" action
    getAttendeesData(events); // <-- starts fetching attendees for `events`, which will still be an empty array
}, []); // <-- [] means run this code once, only when mounted

解决方案是拆分use效果,以便正确处理每个部分。

useEffect(() => {
    getEventsData(); // <-- queues and starts "fetch event IDs" action
}, []); // <-- [] means run this code once, only when mounted

useEffect(() => {
    getAttendeesData(events); // initially fetches attendees for an empty array, but is then called again when `events` is updated with data
}, [events]); // <-- [events] means run this code, when mounted or when `events` changes

接下来,您需要修复getAttendeesData,因为它有一个类似的问题,它最终会在它结束时使用另一个空数组(attendeeInformation)调用setAttendeeInfo(),因为您不会等待它首先填充数据。虽然此数组最终会正确填充数据,但当它填充时,它不会触发重新呈现以实际显示该数据。

const [attendeeInfo, setAttendeeInfo] = useState([]); // <-- should be an array not an object?
const [events, setEvents] = useState([]);

const getAttendeesData = async (events) => {
    console.log(events);

    const fetchAttendeesPromises = events.map(async (event) => {
        const attendeesRef = collection(db, "events", event, "attendees");
        const attendeesSnap = await getDocs(attendeesRef);
        const attendeeInformation = [];

        attendeesSnap.forEach((doc) => {
            const isItMentor = doc.data().isMentor ? "Yes" : "No";
            const isItMentee = doc.data().isMentee ? "Yes" : "No";
            const attendeeData = {
                name: doc.id,
                mentor: isItMentor,
                mentee: isItMentee,
            };

            attendeeInformation.push(attendeeData);
        })

        return attendeeInformation; // also consider { event, attendeeInformation }
    })

    // wait for all attendees to be fetched first!
    const attendeesForAllEvents = await Promises.all(fetchAttendeesPromises)
      .then(attendeeGroups => attendeeGroups.flat()); // and flatten to one array

    // console.log(attendeesForAllEvents);
    setAttendeeInfo(attendeesForAllEvents);
}

以基本且不完整的方式(见下文)应用这些变更,可得出:

// place these outside your component, they don't need to be recreated on each render
const getEventsData = async () => { /* ... */ }
const getAttendeesData = async (events) => { /* ... */ }

export const YourComponent = (props) => {
  const [attendeeInfo, setAttendeeInfo] = useState(null); // use null to signal "not yet loaded"
  const [events, setEvents] = useState(null); // use null to signal "not yet loaded"
  const loading = events === null || attendeeInfo === null;

  useEffect(() => {
    getEventsData();
  }, []);

  useEffect(() => {
    if (events !== null) // only call when data available
      getAttendeesData(events);
  }, [events]);

  // hide component until ready
  // consider rendering a spinner/throbber here while loading
  if (loading)
    return null;

  return (
    /* render content here */
  )
}

因为getEventsData()getAttendeesData()是Promises,所以您应该使用useAsyncEffects实现,例如@react-ook/asyncuse-async-Effects,以便您可以处理任何中间状态,例如加载、不正确的身份验证、完成前卸载和其他错误(上述片段中未涵盖)。此线程包含有关此主题的更多详细信息。

 类似资料:
  • 我现在有一个firestore,看起来像这样: 我使用的是,我试图获取“报告”集合中的所有文档。 我可以得到一个报告: 但我无法得到整个子集合 这可能吗?我是新手,所以这可能是一个愚蠢的问题。 谢谢 编辑控制台中收到的错误消息是: 我不确定权限,我没有访问权限,但如果是权限问题,我很困惑,我可以从集合中获取一个文档,但找不到获取所有文档的方法

  • 我正在构建javascript服务,我想从“集合名称”和“文档ID数组”的输入中从firestore中获取所有子集合文档详细信息。 请求有效负载调用我的服务: 我需要搜索所有此msgId的所有子集合(所有文档的通用名称)文档。 我的消防仓库结构如下所示 示例: 在这种情况下,我需要获取msgId“11”,“22”的数据,这些数据在firestore中可用,其他值应发送null。你能不能帮你帮忙,不

  • 我想从一个集合中得到所有的文件,然后用它们,得到他们的身份证。这里我的集合如何是用户集合,它只是一个集合和多个文档。我试了一下,但不起作用: 更新

  • 如何使用Spring FirestoreReactiveRepository从子集合中获取文档? 问题是:如何动态地将子集合名称或路径指定给@Document annotation? 我的firestore系列:(城市是一级系列,公寓是本系列的子系列) 波乔市 POJO公寓是: 从城市收集中获取数据的CityRepository 调用findById(nyc)时,公寓返回空值。我想在城市对象中填充

  • 我正在使用Java开发一个Android应用程序,我使用firestore数据库,我有一个名为用户位置的集合,其结构类似于照片: 分贝 我的问题是,当一个用户改变他的位置或一个新用户进入一个已经存在的位置(其他用户有相同的位置)时,它会创建一个新文档(如在“oran, algerie”中)。当我添加新用户并更新文档时,我想使用,但问题是我无法以正常方式检索根集合的所有文档: 它返回null。我尝试

  • 嗨,我从javascript和react-native开始,我花了几个小时试图解决这个问题。有人能告诉我如何从firestore收集处获得所有文件吗? 我一直在尝试这个: 日志1打印所有对象(一个接一个),但日志2没有定义,为什么?