【问题标题】:Firestore nested onSnapshot await/asyncFirestore 嵌套 onSnapshot 等待/异步
【发布时间】:2020-10-17 19:19:07
【问题描述】:

我在使用 onSnapshot 方法时遇到问题。它不会等待第二次 onsnapshot 调用,因此返回值不正确。在第二次 onsnapshot 调用中获取的用户将在稍后返回值时显示在控制台日志中。

如果您更喜欢其他结构,我愿意接受任何解决方案和建议!!:) 谢谢大家。

控制台日志:https://imgur.com/a/vhm61nu.png

export const FirebaseGetStrikeLists2 = async (houseId: string) => {
    let strikes: StrikeListDocument[] = [];

    firestore()
        .collection(FirebaseConstraints.HouseCollection)
        .doc(houseId)
        .collection(FirebaseConstraints.StrikeSubCollection)
        .onSnapshot(async x => {
            x.forEach(async x => {
                const strikeListDocument = x.data() as StrikeListDocument
                strikeListDocument.users = []
                strikeListDocument.id = x.id;

                x.ref.collection(FirebaseConstraints.UserCollection).onSnapshot(
                    async x => {
                        let strikeListUsers: StrikeListDocumentUser[] = [];
                        x.forEach(async y => {
                            let userDocument = y.data() as StrikeListDocumentUser;
                            strikeListUsers.push(userDocument)
                        })
                        await Promise.all(strikeListUsers)
                        console.log('users found: ', strikeListUsers.length)
                        strikeListDocument.users = strikeListUsers
                    })
                console.log('users set in array: ', strikeListDocument.users.length)
                strikes.push(strikeListDocument)
            })
        })
    return strikes;
}

我的 Firestore 结构如下所示: /houses/{HouseID}/strikelists/{StrikeListID}/users/{UserID}

编辑:

我已经让它在不同的班级工作。首先我试图让代码等待然后返回它,但找不到解决方案。所以我在结构上做了一些改变。每当接收到数据时,它都会更新状态(必须在同一个文件中)。我正在使用 mobx 作为可观察对象。

ps:此代码也可以从 UI 组件中调用,并将其更改为 useState 挂钩。

现在看起来像这样:

@observable private _strikeLists: StrikeListDocument[] | undefined;

export const firestoreStrikeListSubscription = (houseId: string) => {
    firestore()
        .collection(FirebaseConstraints.HouseCollection)
        .doc(houseId)
        .collection(FirebaseConstraints.StrikeSubCollection)
        .onSnapshot(x => {
            x.forEach(x => {
                let strikeListDocument = x.data() as StrikeListDocument
                strikeListDocument.id = x.id;

                x.ref.collection(FirebaseConstraints.UserCollection).onSnapshot(
                    x => {
                        let strikeListDocumentUsers: StrikeListDocumentUser[] = []
                        x.forEach(y => {
                            let userDocument = y.data() as StrikeListDocumentUser;
                            strikeListDocumentUsers.push(userDocument)
                        })
                        const strikeList = this._strikeLists?.find(x => x.id == strikeListDocument.id)
                        if (strikeList)
                            strikeList.users = strikeListDocumentUsers
                    })
                this._strikeLists?.push(strikeListDocument)
            })
        })
}

【问题讨论】:

    标签: typescript firebase react-native google-cloud-firestore async-await


    【解决方案1】:

    onSnapshot() 返回void

    https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#onsnapshot

    你能试试下面的代码吗?

    // In the Same Class
    const [strikes, setStrikes] = useState<StrikeListDocument[]>([]);
    
    export const FirebaseGetStrikeLists2 = async (houseId: string) => {
      firestore()
        .collection(FirebaseConstraints.HouseCollection)
        .doc(houseId)
        .collection(FirebaseConstraints.StrikeSubCollection)
        .onSnapshot(async x => {
          let strikes: StrikeListDocument[] = [];
    
          x.forEach(async x => {
            const strikeListDocument = x.data() as StrikeListDocument;
            strikeListDocument.users = [];
            strikeListDocument.id = x.id;
    
            x.ref
              .collection(FirebaseConstraints.UserCollection)
              .onSnapshot(async x => {
                let strikeListUsers: StrikeListDocumentUser[] = [];
                x.forEach(async y => {
                  let userDocument = y.data() as StrikeListDocumentUser;
                  strikeListUsers.push(userDocument);
                });
                await Promise.all(strikeListUsers);
                console.log("users found: ", strikeListUsers.length);
                strikeListDocument.users = strikeListUsers;
              });
            console.log("users set in array: ", strikeListDocument.users.length);
            strikes.push(strikeListDocument);
          });
    
          // you should set state here. setStrikes() is useState returns.
          setStrikes(strikes);
        });
    };
    

    【讨论】:

    • 您好,感谢您的回复。现在返回类型是 void。在商店类中,我将一个可观察属性设置为返回值。
    • 感谢您的更新,我也有同样的想法!!:) 我已经编辑了我的帖子。我认为这是最好的方法,但它更喜欢代码拆分。你怎么看?:)
    • 对不起,我还没用过mobx。但是 LGTM。
    猜你喜欢
    • 1970-01-01
    • 2018-06-25
    • 2018-06-04
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-04
    • 1970-01-01
    相关资源
    最近更新 更多