猿问

未从 firestore 获取数据

我尝试从 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.js


import { 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;


当年话下
浏览 123回答 2
2回答

慕田峪4524236

我认为你已经非常接近预期的行为了。我的处理方法如下: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 };};

红颜莎娜

我需要有关“useFirestore”代码的更多信息,但您至少应该这样编写代码。不要列出 firestore 上的每个文档来获取一个(您为每个读取请求付费)在 useEffect 中加载文档,而不是在外部useEffect 必须依赖于 id&nbsp; &nbsp;const Component = (props) => {&nbsp; &nbsp; &nbsp; &nbsp;const id = props.match.params.id;&nbsp; &nbsp; &nbsp; &nbsp;const firestore = //;&nbsp; &nbsp; &nbsp; &nbsp;const [book, bookSet] = useState(false);&nbsp; &nbsp; &nbsp; &nbsp;useEffect(() => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//Depending on useFirestore code&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;firestore.collections('books').doc(id)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.then( snapshot => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ( !snapshot.exists ) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bookSet(null);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bookSet(snapshot.data());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;});&nbsp; &nbsp; &nbsp; &nbsp;}, [id]);&nbsp; &nbsp; &nbsp; &nbsp;if( book === false) return <p>Loading</p>&nbsp; &nbsp; &nbsp; &nbsp;if (!book) return <p>Not exists</p>&nbsp; &nbsp; &nbsp; &nbsp;return <p>Display it</p>;&nbsp; &nbsp;};编辑这是我对你的“useFirestore”钩子的猜测&nbsp; const Component = (props) => {&nbsp; &nbsp; &nbsp; const id = props.match.params.id;&nbsp; &nbsp; &nbsp; const { docs, loading } = useFirestore('books');&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; useEffect(() => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if( loading) console.log('Loading');&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const book = docs && docs.filter(doc => doc.id === id);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log({book});&nbsp; &nbsp; &nbsp; },[loading, docs, id]);&nbsp; };
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答