我正在尝试显示用户关注的任何人的帖子:
代码如下:
constructor() {
super();
this.firestoreRef = Firebase.firestore().collection('following').doc(Firebase.auth().currentUser.uid).collection('following');
this.state = {
isLoading: true,
followingPosts: [],
};
}
componentDidMount() {
this.setState({isLoading: true})
this.unsubscribe = this.firestoreRef.onSnapshot(this.getCollection);
}
componentWillUnmount(){
this.unsubscribe();
}
getCollection = async (querySnapshot) => {
const followingPosts = [];
querySnapshot.forEach(async (res) => {
await Firebase.firestore()
.collection('globalPosts')
.where("uid", "==", res.data().uid)
.onSnapshot(function(query) {
query.forEach((doc) => {
const {
..Fields
} = doc.data();
followingPosts.push({
key: doc.id,
..Fields
});
})
followingPosts.sort(function(a,b){
return b.date_created.toDate() - a.date_created.toDate()
})
});
})
this.setState({
followingPosts,
isLoading: false,
})
}
问题在于设置状态。如果“以下帖子”数组为空,我会呈现这个:
if (this.state.followingPosts.length == 0) {
return(
<View style={styles.emptyContainer}>
<Text style = {styles.buttonText}>following feed coming soon!</Text>
<TouchableOpacity
style = {styles.button}
onPress={() => this.onShare()} >
<Text style = {styles.buttonText}>invite friends to traderank</Text>
</TouchableOpacity>
</View>
)}
如果没有,我会渲染平面列表:
return (
<View style={styles.view}>
<FlatList
data={this.state.followingPosts}
renderItem={renderItem}
keyExtractor={item => item.key}
contentContainerStyle={{ paddingBottom: 50 }}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
onRefresh={this._refresh}
refreshing={this.state.isLoading}
/>
</View>
)
当前数组始终为“空”,因为我正在设置状态 OUTSIDE 查询快照。
但是当我将 setState
移到 querySnapshot
内部时:
querySnapshot.forEach(async (res) => {
await Firebase.firestore()
.collection('globalPosts')
.where("uid", "==", res.data().uid)
.onSnapshot(function(query) {
query.forEach((doc) => {
const {
...
} = doc.data();
followingPosts.push({
key: doc.id,
...
});
})
followingPosts.sort(function(a,b) {
return b.date_created.toDate() - a.date_created.toDate()
})
console.log(followingPosts)
this.setState({ <------------- here
followingPosts,
isLoading: false,
})
}.bind(this))
})
console.log(followingPosts)
帖子显示正常,但是当当前用户关注的用户发布帖子时,应用程序崩溃,因为帖子是如何写入 firestore 的:
(从用户创建帖子的位置):
await Firebase.firestore()
.collection('globalPosts')
.add({
uid: this.state.uid
})
.then((docRef) => this.uploadToStorage(docRef.id))
.catch(function(error) {
console.error("Error storing and retrieving image url: ", error);
});
await Firebase.firestore()
.collection('globalPosts')
.doc(this.state.postID)
.set ({
... More Fields
})
.catch(function(error) {
console.error("Error writing document to global posts: ", error);
});
由于“Following”中的querySnapshot一直在监听firestore,因为前半部分的创建代码,我一写帖子就崩溃了:
await Firebase.firestore()
.collection('globalPosts')
.add({
uid: this.state.uid <------------------------- only the UID is added initially
})
.then((docRef) => this.uploadToStorage(docRef.id))
.catch(function(error) {
console.error("Error storing and retrieving image url: ", error);
});
帖子已添加到 globalPosts
,但尚未添加其余字段。
我能想到的唯一解决方案是:
在查询快照之外设置状态,但是当我尝试这样做时,帖子没有显示,因为 followingPosts.length
为 0 并且状态没有在 querySnapshot
之外更新
弄清楚如何卸载组件,看起来组件没有卸载,所以监听器一直在监听,这就是导致崩溃的原因
-关于此的说明。我有一个 globalPosts
供稿,所有内容都 100% 正常工作,然后在我的“以下”供稿中尝试几乎相同的实现时,当用户发布新帖子时应用程序崩溃
编辑:我现在正在深入了解为什么要安装组件并因此在应该卸载组件时进行监听。这可能是我崩溃的原因!
答案 0 :(得分:1)
您的代码有点偏离,因为您为当前用户关注的每个用户创建了一个侦听器,并为他们帖子的每个更改创建了一个侦听器。这将影响性能并使 Firestore 的成本增加两倍。对于当前用户感兴趣的帖子,您应该只有一个监听器。
这个想法是,当组件安装时,您使用正常的 get 方法而不是侦听器获取当前用户关注的所有用户,然后将此用户添加到状态。同时你应该有一个 globalPosts 的监听器,它通过过滤帖子所有者的字段来获取帖子。
像这样:
// get users that current user is following
firestore
.collection("users")
.doc(auth.currentUser.uid)
.get().then((doc) => this.setState({following: [...doc.data().following]}))
// set a listner for those users' posts and take advantage of **in** operator
this.unsubscribeFirestore = firestore
.collection("globalPosts")
.where("owner", "in", following)
.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
this.setState({
followingPosts: [
...this.state.followingPosts,
change.doc.data(),
],
});
}
});
});