繁体   English   中英

尝试使用用户配置文件中的数组一次从 React 中的 Firestore 查询多个文档

[英]Trying to query multiple documents from Firestore in React at once, using an array from the users profile

这是我当前的代码:

useEffect(() => {
    profile.familyCode.forEach((code) => {
      console.log(code._id)
      onSnapshot(query(collection(db, "group-posts", code._id, "posts"), orderBy("timestamp", "desc")
      ),
      (querySnapshot) => {
        const posts = querySnapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
        setMessages([...messages, posts])        
      }
      )
    })

有两个 code._id's,目前它只是从其中一个设置我的消息。 我在这里错过了什么?

我尝试使用一些 firestores 逻辑表达式来做同样的事情但没有成功。 这样我至少可以拉出其中的一些,但我想从两个代码中拉出所有帖子。_id

您错过了setMessages不会立即更新messages本身的事实。 因此, messages在这里使用旧的(或初始值)进行闭包捕获,并且调用setMessages只会覆盖先前onSnapshot之前设置的内容。

下一期 - onSnapshot返回unsubscribe函数,应该调用该函数来停止侦听器。 或者你会得到一些错误和内存泄漏。

这是一个可能的解决方案 custom hook的快速编写(并没有真正测试过)的例子。

export function useProfileFamilyGroupPosts(profile) {
  const [codeIds, setCodeIds] = useState([]);
  const [messagesMap, setMessagesMap] = useState(new Map());

  const messages = useMemo(() => {
    if (!messagesMap || messagesMap.size === 0) return [];
    // Note: might need some tweaks/fixes. Apply .flatMap if needed.
    return Array.from(messagesMap).map(([k, v]) => v);
  }, [messagesMap])

  // extract codeIds only, some kind of optimization
  useEffect(() => {
    if (!profile?.familyCode) {
      setCodeIds([]);
      return;
    }
    const codes = profile.familyCode.map(x => x._id);
    setCodeIds(curr => {
      // primitive arrays comparison, replace if needed.
      // if curr is same as codes array - return curr to prevent any future dependent useEffects executions
      return curr.sort().toString() === codes.sort().toString() ? curr : codes;
    })
  }, [profile])

  useEffect(() => {
    if (!codeIds || codeIds.length === 0) {
      setMessagesMap(new Map());
      return;
    }
    const queries = codeIds.map(x => query(collection(db, "group-posts", x, "posts"), orderBy("timestamp", "desc")));
    const unsubscribeFns = queries.map(x => {
      return onSnapshot(x, (querySnapshot) => {
        const posts = querySnapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
        // update and re-set the Map object.
        setMessagesMap(curr => {
          curr.set(x, posts);
          return new Map(curr)
        })
      });
    });

    // we need to unsubscribe to prevent memory leaks, etc
    return () => {
      unsubscribeFns.forEach(x => x());
      // not sure if really needed
      setMessagesMap(new Map());
    }
  }, [codeIds]);

  return messages;
}

这个想法是用一个Map (或只是{}键值对象)来存储来自快照侦听器的数据,然后将该key-value平铺到生成的messages数组中。 并从钩子中返回这些消息。

用法将是

const messages = useProfileFamilyGroupPosts(profile);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM