代码之家  ›  专栏  ›  技术社区  ›  Yusuf Yeşilyurt

无法在自定义挂钩中将Firestore数据设置为State

  •  0
  • Yusuf Yeşilyurt  · 技术社区  · 4 年前

    在我的自定义挂钩中,我得到了消防商店收藏的所有图像。在我尝试获取图像的元数据之前,这一直很好。当我添加getMetaData函数时,即使数据在数组中看起来很好,我也无法将数据设置为state。 请查看代码。

    import { useState, useEffect } from "react";
    import { firebaseFireStore } from "../firebase/config";
    import { storage } from "../firebase/config";
    import { ref, getMetadata } from "firebase/storage";
    
    const useFirestore = (collection) => {
      const [docs, setDocs] = useState([]);
    
      useEffect(() => {
        const unsub = firebaseFireStore
          .collection(collection)
          .onSnapshot((snap) => {
            let documents = [];
            snap.forEach((doc) => {
              const forestRef = ref(storage, doc.data().url);
              getMetadata(forestRef)
                .then((metadata) => {
                  documents.push({ ...doc.data(), metadata, id: doc.id });
                  return documents;
                })
                .catch((error) => {
                  console.log(error);
                });
            });
            setDocs(documents);
            console.log(docs); // [] EMPTY ARRAY, PROBLEM IS HERE.
            console.log(documents); // [] length:13 data is complete inside.  
          });
    
        return () => unsub();
        // this is a cleanup function that react will run when
        // a component using the hook unmounts
      }, []);
    
      return { docs };
    };
    
    export default useFirestore;
    

    所以,即使文档数组中有包含元数据的数据,也不能将其设置为文档的状态。 感谢您的帮助。

    0 回复  |  直到 4 年前
        1
  •  2
  •   Drew Reese    4 年前

    您无法登录 docs 状态 正确的 因为React异步处理状态更新。但这并不完全是你的问题,也不是你真正想要解决的问题。代码在快照上进行映射,并将异步请求排入队列以检索元数据,并异步更改 documents 在React a中更新的数组 长的 *很久以前。这个 console.log(documents) 只是在稍后浏览器处理日志缓冲区时暴露这种突变。

    为了解决问题,我建议宣布 snapshot.forEach 回调 async 这样它就可以等待 getMetadata 调用以解决问题。使用功能状态更新在每个文档与元数据解析时对其进行浅层合并。

    示例:

    useEffect(() => {
      const unsubscribe = firebaseFireStore
        .collection(collection)
        .onSnapshot((snap) => {
          snap.forEach(async (doc) => {
            try {
              const forestRef = ref(storage, doc.data().url);
              const metadata = await getMetadata(forestRef);
              setDocs(documents => [
                ...documents,
                { ...doc.data(), metadata, id: doc.id }
              ]);
            } catch(error) {
              console.log(error);
            };
          });  
        });
    
      return unsubscribe;
    }, []);
    

    *“很久以前”->以前的某个渲染周期。