簡體   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