REACT + FIRESTORE:在REACT组件中监听firebase集合的变化,以自动更新反应状态



我在firestore中有一个帖子集合,从中我可以获得列表[user1, user2,…]中用户创建的所有帖子。我可以在下面的方法中使用onSnapshot来监听集合中的变化:

export default function Feed({ friendList }) {
// currentUser context
const { currentUser } = useAuth();
// array to save posts from database
const [posts, setPosts] = useState([]);
// function to fetch data from database
useEffect(() => {
db.collection('posts')
.where('userId', 'in', [...friendList])
.orderBy('timestamp', 'desc')
.onSnapshot((snapshot) => {
setPosts(
snapshot.docs.map((doc) => ({
id: doc.id,
post: doc.data(),
}))
);
});
}, []);
return (
<div className='feed'>
{currentUser ? (
<div className='feed_container'>
{posts.map(({ id, post }) => {
return (
<Post
key={id}
id={id}
userProfileURL={post.userProfileURL}
username={post.username}
displayName={post.displayName}
photoURL={post.photoURL}
/>
);
})}
</div>

但是如果friendList有超过10个元素,这个'in'查询将不起作用。因此,我可以使用以下承诺从集合中获取所需的文档:

useEffect(() => {
getPostsFromFriendsList(friendList);
}, []);
async function getPostsFromFriendsList(friendList){
const promises = [];
for (let i = 0; i < friendList.length; i++) {
promises.push(getPosts(friendList[i]));
}
const postsForHomeFeed = await Promise.all(promises);
const array = [];

for (let i = 0; i < postsForHomeFeed.length; i++) {
postsForHomeFeed[i].docs.map((doc) => {
array.push({
id: doc.id,
post: doc.data(),
});
});
}
setPosts(array);
}
function getPosts(userId) {
return new Promise((resolve, reject) => {
db.collection('posts')
.where('userId', 'in', [userId])
.onSnapshot((snapshot) => {
resolve(snapshot);
});
});
}

但是,如果在我的firestore集合中添加或删除了一个帖子,我不再能够侦听数据库中的变化来更新我的反应状态以相应地呈现。我如何在第二段代码中为promises解决方案设置useEffect,以便每次firestore集合发生变化时都可以更新我的反应状态?谢谢你。

您需要让侦听器保持打开状态,并在每次触发它们时更新状态,并根据postids合并数据,如下所示:

useEffect(() => {
getPostsFromFriendsList(friendList);
}, []);
//source: https://stackoverflow.com/questions/7146217/merge-2-arrays-of-objects
const merge = (a, b, prop) => {
var reduced = a.filter(
(aitem) => !b.find((bitem) => aitem[prop] === bitem[prop])
);
return reduced.concat(b);
};
async function getPostsFromFriendsList(friendList) {
const promises = [];
for (let i = 0; i < friendList.length; i++) {
db.collection("posts")
.where("userId", "in", [friendList[i]])
.onSnapshot((snapshot) => {
const array = [];
snapshot.docs.map((doc) => {
array.push({
id: doc.id,
post: doc.data(),
});
});
setPosts(merge([...posts], array, "id"));
});
}
}

useEffect块中使用onSnapshot简单的例子;

useEffect(() => {
onSnapshot(collection(db, "profiles"), (snapshot) => {
setProfiles(snapshot.docs.map((doc)=>({...doc.data(), id: doc.id})))
})
console.log(profiles);
});

profiles状态将始终包含更新的项。

最新更新