[英]Not getting data from the firestore
I tried to fetch docs from the firestore, it returns an empty array but when I run console.log(docs);我试图从 firestore 获取文档,它返回一个空数组但是当我运行 console.log(docs); outside the declared function, it returns the actual array.
在声明的函数之外,它返回实际的数组。 I know this error occurs because my useEffect function runs first before getting the docs from the firestore.
我知道发生此错误是因为我的 useEffect 函数在从 firestore 获取文档之前首先运行。 I want to know how to fix this issue.
我想知道如何解决这个问题。
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使用Firestore.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;
I need more informations on the 'useFirestore' code but you should at least write your code like that.我需要有关“useFirestore”代码的更多信息,但您至少应该像这样编写代码。
do not list every document on firestore to just get one (you pay for each read request)不要在 firestore 上列出每个文档来获取一个(您为每个读取请求付费)
load the document in useEffect, not outside在 useEffect 中加载文档,而不是在外部
useEffect must depend on the id 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>; };
Edition版
Here is my guess with your 'useFirestore' hooks这是我对你的“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]);
};
I think you are pretty close to getting the expected behaviour.我认为您非常接近获得预期的行为。 Here's how I'd approach it:
这是我如何处理它:
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
};
The useFirestore
hook looks almost fine, only one remark: right now even if you change the collection
parameter, the snapshot listener won't change. useFirestore
钩子看起来几乎没问题,只有一句话:现在即使您更改collection
参数,快照侦听器也不会更改。 You might want to do this:你可能想要这样做:
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]);
If you want the useFirestore
hook to only query for a particular book, you need to change the hook to accept and use a document ID, something like this:如果您希望
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 };
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.