在useEffect中有多个Firebase侦听器,并将新事件推送到状态



我想检索与用户位置相关的产品列表,为此我使用Geofirestore并更新我的Flatlist

当我有前10个最接近的集合时,我循环得到每个子集合。

我设法更新我的状态,但每次我的集合在其他地方被修改,而不是更新我的列表,它复制了我已经修改的对象,并在我的列表的末尾添加它(更新),并保留旧对象在该列表中。

例如:

const listListeningEvents = {
A: {Albert, Ducon}
B: {Mickael}
}

另一个用户修改了'A'并删除了'Ducon',我将得到:

const listListeningEvents = {
A: {Albert, Ducon},
B: {Mickael},
A: {Albert}
}

而不是:

const listListeningEvents = {
A: {Albert},
B: {Mickael},
}

这是我的使用效果:

useEffect(() => {
let geoSubscriber;
let productsSubscriber;
// 1. getting user's location
getUserLocation()
// 2. then calling geoSubscriber to get the 10 nearest collections
.then((location) => geoSubscriber(location.coords))
.catch((e) => {
throw new Error(e.message);
});
//Here
geoSubscriber = async (coords) => {
let nearbyGeocollections = await geocollection
.limit(10)
.near({
center: new firestore.GeoPoint(coords.latitude, coords.longitude),
radius: 50,
})
.get();
// Empty array for loop
let nearbyUsers = [];
// 3. Getting Subcollections by looping onto the 10 collections queried by Geofirestore
productsSubscriber = await nearbyGeocollections.forEach((geo) => {
if (geo.id !== user.uid) {
firestore()
.collection("PRODUCTS")
.doc(geo.id)
.collection("USER_PRODUCTS")
.orderBy("createdDate", "desc")
.onSnapshot((product) => {
// 4. Pushing each result (and I guess the issue is here!)
nearbyUsers.push({
id: product.docs[0].id.toString(),
products: product.docs,
});
});
}
});
setLoading(false);
// 4. Setting my state which will be used within my Flatlist
setListOfProducts(nearbyUsers);
};
return () => {
if (geoSubscriber && productsSubscriber) {
geoSubscriber.remove();
productsSubscriber.remove();
}
};
}, []);

多年来我一直在努力使它正常工作,我快疯了。

所以我梦到了两件事:

  1. 能够在不复制修改对象的情况下更新我的状态
  2. (奖励)当我向下滚动到我的Flatlist时,找到一种方法来获得下一个最近的10个点。

在我看来,问题在于nearbyUsers的类型。它被初始化为数组=[],当你将其他对象推入它时,只需在末尾添加新项(数组引用)。

在这种情况下,数组不是很方便,因为要实现目标,需要检查数组中的每个现有项目,并找到是否有适当的id更新它。

我认为在这种情况下最方便的将是Map(地图参考)。Map按键索引,因此可以只获取特定的值而不搜索它。

我将尝试调整它以呈现代码(不是所有行,只是更改):

  1. 修改键为id值为products的映射对象类型:
let nearbyUsersMap =  new Map();
  1. 使用set方法代替push方法更新特定密钥的产品:
nearbyUsersMap.set(product.docs[0].id.toString(), product.docs);
  1. 最后将Map转换为Array以实现在进一步代码中使用的相同对象:
let nearbyUsers = Array.from(nearbyUsersMap,  ([id, products]) => ({ id, products }));
setListOfProducts(nearbyUsers);

这应该工作,但我没有任何游乐场来测试它。如果出现任何错误,请尝试解决它们。我对geofirestore不是很熟悉,所以我不能帮助你更多。当然,还有其他方法可以实现目标,但是这应该在本文中工作,并且只需要进行一些更改。

最新更新