【发布时间】:2020-11-29 11:35:03
【问题描述】:
简介
我的 FireStore 中存储了一个带有道具“日期”的项目列表。在客户端代码中,我有一个 FlatList,其中包含所有按“日期”排序的项目(第一个元素是最近的项目,第二个元素是我在第一个出现的元素之前上传的项目,...)
问题是我只得到 5 个项目(但这是因为我不想一次得到 100 个项目),而且我不知道如何将它与 FlatList 的 onEndReached 结合起来(因为它是一个监听器组件卸载时必须分离的代理)以按照相同的顺序获取更多项目。
任何想法如何使这项工作?我在可能需要更改的代码行上注释了“
FIRESTORE 数据库
Items -> user.uid -> userItems:
{
...
date: 1/1/1970
},
{
...
date: 2/1/1970
},
...
{
...
date: 31/1/1970
}
我的 FLATLIST 必须如何呈现:
按顺序排列项目:
{ // The most recent one appears at the top of the list
...
date: 31/1/1970
},
...
{
...
date: 2/1/1970
},
{
...
date: 1/1/1970
},
代码
const [startItem, setStartItem] = useState(null);
useEffect(() => {
const { firebase } = props;
let itemsArray = [];
// Realtime database listener
const unsuscribe = firebase // <------- With this I get the 5 most recent items when component mounts, or only one if the user has uploaded it after the component mounts
.getDatabase()
.collection("items")
.doc(firebase.getCurrentUser().uid)
.collection("userItems")
.orderBy("date") // Sorted by upload date <------------------
.startAfter(startItem && startItem.date) // <-----------------------
.limitToLast(5) // To avoid getting all items at once, we limit the fetch to 5 items <----------
.onSnapshot((snapshot) => {
let changes = snapshot.docChanges();
changes.forEach((change) => {
if (change.type === "added") {
// Get the new item
const newItem = change.doc.data();
// Add the new item to the items list
itemsArray.unshift(newItem);
}
});
// Reversed order so that the last item is at the top of the list
setItems([...itemsArray]); // Shallow copy of the existing array -> Re-render when new items added
setIsLoading(false);
// Change the start item
setStartItem(itemsArray[itemsArray.length - 1]);
});
return () => {
// Detach the listening agent
unsuscribe();
};
}, []);
...
<CardList data={items} isLoading={isLoading} onEndReached={/*how to call the function 'unsuscribe'? */} /> // <----------
我需要的是在到达列表末尾时获取另外 5 个最近的项目,然后将它们添加到列表的 底部
更新(我目前最好的方法)
const [items, setItems] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [start, setStart] = useState(null);
const limitItems = 5;
const getItems = () => {
/*
This function gets the initial amount of items and returns a
real time database listener (useful when a new item is uploaded)
*/
const { firebase } = props;
// Return the realtime database listener
return firebase
.getDatabase()
.collection("items")
.doc(firebase.getCurrentUser().uid)
.collection("userItems")
.orderBy("date") // Sorted by upload date
.startAt(start)
.limitToLast(limitItems)
.onSnapshot((snapshot) => {
let changes = snapshot.docChanges();
let itemsArray = [...items]; // <------- Think the error is here
console.log(`Actual items length: ${itemsArray.length}`); // <-- Always 0 WHY?
console.log(`Fetched items: ${changes.length}`); // 5 the first time, 1 when a new item is uploaded
changes.forEach((change) => {
if (change.type === "added") {
// Get the new fetched item
const newItem = change.doc.data();
// Add the new fetched item to the head of the items list
itemsArray.unshift(newItem);
}
});
// The last item is at the top of the list
setItems([...itemsArray]); // Shallow copy of the existing array -> Re-render when new items added
// Stop loading
setIsLoading(false);
// If this is the first fetch...
if (!start && itemsArray.length) {
// Save the startAt snapshot
setStart(itemsArray[itemsArray.length - 1].date);
}
});
};
const getMoreItems = () => {
/*
This funciton gets the next amount of items
and is executed when the end of the FlatList is reached
*/
const { firebase } = props;
// Start loading
setIsLoading(true);
firebase
.getDatabase()
.collection("items")
.doc(firebase.getCurrentUser().uid)
.collection("userItems")
.orderBy("date", "desc")
.startAfter(start)
.limit(limitItems)
.get()
.then((snapshot) => {
let itemsArray = [...items];
snapshot.forEach((doc) => {
// Get the new fethed item
const newItem = doc.data();
// Push the new fetched item to tail of the items array
itemsArray.push(newItem);
});
// The new fetched items will be at the bottom of the list
setItems([...itemsArray]); // Shallow copy of the existing array -> Re-render when new items added
// Stop loading
setIsLoading(false);
// Save the startAt snapshot everytime this method is executed
setStart(itemsArray[itemsArray.length - 1].date);
});
};
useEffect(() => {
// Get a initial amount of items and create a real time database listener
const unsuscribe = getItems();
return () => {
// Detach the listening agent
unsuscribe();
};
}, []);
使用此代码,我可以第一次获取初始数量的项目,然后在到达 FlatList 末尾时获取下一个数量。但是由于某种原因,监听器内部的状态没有更新......所以当一个新项目被上传时,我之前得到的所有项目都会从 FlatList 中消失,并且当到达 FlatList 的末尾时它们会再次被收集。
【问题讨论】:
-
我不明白这里有什么问题。您限制为 5 个文档,因此您最多获得 5 个文档。为什么这与您的预期不同?您的问题是“问题是我无法获得完整的项目列表”,这让我感到困惑,因为您选择了限制结果。
-
是的,我只得到 5 个,但这是因为我不想一次得到 100 个项目。我不知道如何将它与 FlatList 的 onReached 结合起来(因为它是一个侦听器代理,在组件卸载时必须分离)以按照相同的顺序获取更多项目。
-
onEndReached* 抱歉
-
我建议编辑问题以包含这些详细信息,并明确您卡在哪里。
-
好吧,我已经更新了。我想这是一种常见的情况,但我不知道如何解决。
标签: javascript reactjs firebase react-native google-cloud-firestore