为了账号安全,请及时绑定邮箱和手机立即绑定

未从 firestore 获取数据

未从 firestore 获取数据

当年话下 2023-06-29 15:52:57
我尝试从 firestore 获取文档,它返回一个空数组,但是当我运行 console.log(docs); 时 在声明的函数之外,它返回实际的数组。我知道发生此错误是因为我的 useEffect 函数在从 firestore 获取文档之前首先运行。我想知道如何解决这个问题。const Component = (props) => {    const { docs } = useFirestore('books');    const id = props.match.params.id;        const loadContent = () => {        const book = docs && docs.filter(doc => doc.id === id);        console.log(book); //not getting book from the docs because docs is empty    }        useEffect(() => {        async function getContent(){            await loadContent();        }        getContent()    },[]);};useFirestore.jsimport { useState, useEffect } from 'react';import { firestore } from '../config/fbConfig';const useFirestore = (collection) => {    const [docs, setDocs] = useState([]);    const [loading, setLoading] = useState(true);    // getting realtime data from the firebase for books    useEffect(() => {        let unsubscribe = firestore.collection(collection)        // .orderBy('createdAt', 'desc')        .onSnapshot((querySnapshot) => {          const items = [];          querySnapshot.forEach((doc) => {            items.push({...doc.data(), id: doc.id});          });          setDocs(items);          setLoading(false);        });        return unsubscribe;      }, []); // eslint-disable-line react-hooks/exhaustive-deps      return { docs, loading };}export default useFirestore;
查看完整描述

2 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

我认为你已经非常接近预期的行为了。我的处理方法如下:


const Component = props => {

  const { docs } = useFirestore("books");


  const id = props.match.params.id;


  // useMemo - whenever `docs` change, recalculate the book variable.

  // If `docs` don't change, `book` will also not change.

  // Your `docs` will probably change on every snapshot.

  const book = useMemo(() => docs && docs.filter(doc => doc.id === id), [docs]);


  console.log(book);


  useEffect(() => {

    if (book) {

      // Do something with the book, e.g. loadContent(book).

      // Keep in mind that this will run on every snapshot.

      // If you only want to run this once, you'll need an

      // extra state variable to store that the effect was

      // already run, and check it here.

    }

  }, [book]); // The effect will run whenever book changes

};

这个useFirestore钩子看起来几乎没问题,只有一件事:现在即使你改变参数collection,快照监听器也不会改变。您可能想要这样做:


useEffect(() => {

  const unsubscribe = firestore.collection(collection).onSnapshot(snapshot => {

    const items = snapshot.map(doc => ({ ...doc.data(), id: doc.id }));

    setDocs(items);

    setLoading(false);

  });


  return unsubscribe;


  // Whenever `collection` changes, `unsubscribe` will be called, and then this hook

  // will subscribe to the new collection.

}, [collection]);

更新。

如果您希望useFirestore挂钩仅查询特定书籍,则需要更改挂钩以接受并使用文档 ID,如下所示:



const getDoc = doc => ({ ...doc.data(), id: doc.id });


const useFirestore = (collection, docId) => {

  const [docs, setDocs] = useState([]);

  const [loading, setLoading] = useState(true);


  useEffect(() => {

    let subject = firestore.collection(collection);


    if (docId) {

      // If docId is available, listen for changes to a

      // particular document

      subject = subject.doc(docId);

    }


    const unsubscribe = subject.onSnapshot(snapshot => {

      // Notice here that if listening for a particular docId,

      // the snapshot will be that document, not an array.

      // To maintain the interface of the hook, I convert that

      // document to an array with a single item.

      const items = docId ? [getDoc(doc)] : snapshot.map(getDoc);

      setDocs(items);

      setLoading(false);

    });


    return unsubscribe;

  }, [collection, docId]);


  return { docs, loading };

};


查看完整回答
反对 回复 2023-06-29
?
红颜莎娜

TA贡献1842条经验 获得超12个赞

我需要有关“useFirestore”代码的更多信息,但您至少应该这样编写代码。

  • 不要列出 firestore 上的每个文档来获取一个(您为每个读取请求付费)

  • 在 useEffect 中加载文档,而不是在外部

  • useEffect 必须依赖于 id

   const Component = (props) => {

       const id = props.match.params.id;

       const firestore = //;

       const [book, bookSet] = useState(false);


       useEffect(() => {

           //Depending on useFirestore code

           firestore.collections('books').doc(id)

           .then( snapshot => {

               if ( !snapshot.exists ) {

                   bookSet(null);

               } else {

                   bookSet(snapshot.data());

               }

           });

       }, [id]);


       if( book === false) return <p>Loading</p>

       if (!book) return <p>Not exists</p>

       return <p>Display it</p>;

   };

编辑


这是我对你的“useFirestore”钩子的猜测


  const Component = (props) => {

      const id = props.match.params.id;

      const { docs, loading } = useFirestore('books');

      

      useEffect(() => {

          if( loading) console.log('Loading');

          return;


          const book = docs && docs.filter(doc => doc.id === id);

          console.log({book});

      },[loading, docs, id]);

  };


查看完整回答
反对 回复 2023-06-29
  • 2 回答
  • 0 关注
  • 122 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号