首页 > 解决方案 > Firestore 数据未显示在我的平面列表中?

问题描述

我正在尝试显示用户关注的任何人的帖子:

  1. 首先,我查询 firestore 并获取当前用户关注的所有用户的列表
  2. 对于“关注”中的每个用户,我都会收到他们的帖子
  3. 我使用 javascript 排序函数按创建的数据排序他们的帖子

这是代码:

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,但尚未添加其余字段。

我能想到的唯一解决方案是:

  1. 在查询快照之外设置状态,但是当我尝试这样做时,帖子不会显示,因为followingPosts.length它是 0 并且状态不会在外部更新querySnapshot

  2. 弄清楚如何卸载组件,似乎组件没有卸载,所以监听器总是在监听,这就是导致崩溃的原因

-关于这个的注释。我有一个globalPosts提要,一切都 100% 正常工作,然后在我的“关注”提要中尝试几乎相同的实现时,当用户发布新帖子时应用程序崩溃

  1. 改变我创建帖子的方式,我不想这样做

编辑:我现在正在深入了解为什么要安装组件并因此在应该卸载组件时进行监听。这可能是我崩溃的原因!

标签: javascriptreact-nativegoogle-cloud-firestore

解决方案


您的代码有点偏离,因为您为当前用户关注的每个用户创建一个列表器,并在其帖子的每次更改时创建一个列表器。这将影响性能并使 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(),
            ],
          });
        }
      });
    });

推荐阅读