React Native - Firebase onSnaphot + FlatList 分页
Posted
技术标签:
【中文标题】React Native - Firebase onSnaphot + FlatList 分页【英文标题】:React Native - Firebase onSnaphot + FlatList pagination 【发布时间】: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* 抱歉 我建议编辑问题以包含这些详细信息,并明确您卡在哪里。 好吧,我已经更新了。我想这是一种常见的情况,但我不知道如何解决。 【参考方案1】:好吧,经过几个小时的编码,我找到了解决方案。我认为这不是最好的,因为在到达 FlatList 的末尾时使用 onSnapshot 会更好,但我不知道这是否可以通过 Firestore 的 onSnapshot 实现实现。
解决方案基于问题中的“我的最佳方法”代码。
算法:
只是,我第一次创建实时数据库监听器,它只是执行一个 onSnapshot,然后调用我的函数 onItemsCollectionUpdate(将快照作为参数传递),它可以完美地访问应用程序的更新状态(因为它不在侦听器代理中)
当我们在 onItemsCollectionUpdate 中时,我们只是从快照中获取项目并将它们添加到项目状态。
当到达 FlatList 的末尾时,我们只需调用函数“getItems”,它会静态检索 Firestore 数据(我的意思是,使用 Firebase 中的 get 方法)并添加它到项目状态。
当组件卸载时,分离监听代理。
【讨论】:
以上是关于React Native - Firebase onSnaphot + FlatList 分页的主要内容,如果未能解决你的问题,请参考以下文章
用 react-native-firebase 编译 react-native
哪个 Firebase javascript 包应该与 React Native 一起使用?常规的“Firebase Web SDK”还是“react-native-firebase”?
使用 react-native-firebase 在 React Native 上自定义通知
react native [[DEFAULT]] firebaseapp 未初始化 react-native-firebase