将新文档添加到消防仓库集合后打印重复列表



当组件加载时,它会从firestore中的特定集合中提取所有数据,并将其渲染得很好。然后,当我添加一个新文档时,它会添加该文档,但随后会将它们全部打印出来(包括新文档(。

这是我的第一个真正的反应项目,我有点一无所知。我尝试过在组件加载时重置状态,并在不同的时间调用该方法。

import React, { Component } from 'react';
// Database Ref
import Firebase from '../../Config/Firebase';
// Stylesheet
import '../View-Styles/views.scss';
// Componenents
import Post from '../../Components/Post/Post';
import EntryForm from '../../Components/EntryForm/EntryForm';
export class Gym extends Component {
constructor() {
super();
this.collection = 'Gym';
this.app = Firebase;
this.db = this.app.firestore().collection('Gym');
this.state = {
posts: []
};
this.addNote = this.addNote.bind(this);
};

componentDidMount() {
this.currentPosts = this.state.posts;
this.db.onSnapshot((snapshot) => {
snapshot.docs.forEach((doc) => {
this.currentPosts.push({
id: doc.id,
// title: doc.data().title,
body: doc.data().body
});
});
this.setState({
posts: this.currentPosts
});
});
};
addNote(post) {
// console.log('post content:', post );
this.db.add({
body: post
})
}

render() {
return (
<div className="view-body">
<div>
{
this.state.posts.map((post) => {
return(
<div className="post">
<Post key={post.id} postId={post.id} postTitle={post.title} postBody={post.body} />
</div>
)
})
}
</div>
<div className="entry-form">
<EntryForm addNote={this.addNote} collection={this.collection} />
</div>
</div>
)
};
};
export default Gym;

我试图让它只将新文档添加到列表中,而不是用新文档呈现另一个完整的列表。没有错误消息。

您的问题在于componentDidMount()函数和onSnapshot()的使用。每次对集合进行更新时,都会触发任何附加了onSnapshot()的侦听器。在侦听器中,将快照中的每个文档添加到现有列表中。虽然该列表一开始是空的,但在每次后续更改时,该列表都会附加到集合中的所有文档(包括旧文档,而不仅仅是更改(。

当侦听器的快照出现时,有两种方法可以处理它——要么清空现有列表并在每次更改时重新创建它,要么只处理更改(新条目、已删除条目等(。

附带说明:当使用onSnapshot()时,建议存储它返回的"取消订阅"功能(例如this.stopChangeListener = this.db.onSnapshot(...)(。这允许您稍后通过调用someGym.stopChangeListener()来冻结列表的状态,而无需从服务器接收进一步的更新。

重新创建方法

为了简单起见,我建议您使用此方法,除非您要处理大量项目

componentDidMount() {
this.stopChangeListener = this.db.onSnapshot((snapshot) => {
var postsArray = snapshot.docs.map((doc) => {
return {
id: doc.id,
// title: doc.data().title,
body: doc.data().body
});
});
this.currentPosts = postsArray;
this.setState({
posts: postsArray
});
});
};

复制更改方法

此方法受竞争条件的限制,如果处理不正确,则可能会与数据库解除同步

componentDidMount() {
this.stopChangeListener = this.db.onSnapshot((snapshot) => {
var postsArray = this.currentPosts.clone() // take a copy to work with.
snapshot.docChanges().forEach((change) => {
var doc = change.document;
var data = {
id: doc.id,
// title: doc.data().title,
body: doc.data().body
});
switch(change.type) {
case 'added':
// add new entry
postsArray.push(data)
break;
case 'removed':
// delete potential existing entry
var pos = postsArray.findIndex(entry => entry.id == data.id);
if (pos != -1) {
postsArray.splice(pos, 1)
}
break;
case 'modified':
// update potential existing entry
var pos = postsArray.findIndex(entry => entry.id == data.id);
if (pos != -1) {
postsArray.splice(pos, 1, data)
} else {
postsArray.push(data)
}
}
});
this.currentPosts = postsArray; // commit the changes to the copy
this.setState({
posts: postsArray
});
});
};


附带说明:我还考虑将this.currentPosts = ...移到this.setState()函数中。

在Cloud Firestore中使用onSnapshot((时,只能打印添加的数据。对于您的代码,它应该类似于:

snapshot.docChanges().forEach(function(change) {
if (change.type === "added") {
console.log("Newly added data: ", change.doc.data());
}

此外,Firestore不会在每次添加新数据时加载整个集合,文档会被缓存,并且在集合再次更改时会被重用。

有关更多信息,您可以查看此答案。

最新更新