【问题标题】:Retrieve collection + subcollection give me an empty render检索集合 + 子集合给我一个空渲染
【发布时间】:2019-06-17 12:36:03
【问题描述】:

问题

Web 应用启动时,主要任务是检索存储在各种 Firestore 集合和子集合中的所有用户信息。

问题在于,即使我使用 Promise 和 Loading State 来防止空应用呈现,应用也会使用所有集合数据呈现,但具有子集合的集合除外。

过程

- If user is logged 
-- Set Loading Status Active
-- Load Collection A
-- Load Collection B and forEach, load all sub-collection
-- Load Collection C
-- Set Loading Status Inactive

此时,应用程序被渲染,但只有集合 A 和集合 C。集合 B 已加载(我可以通过 Redux Logs 看到它)但在应用程序中看不到。

仅当我更改组件状态(例如打开/关闭菜单)时才会出现这些数据。

一些代码

以下是我检索带有子集合的集合的方法:


export function setCompanyJobs(user) {

    return {
        type: "SET_COMPANY_JOBS",
        payload: loadCompanyJobs(user),
    };
}

检索主集合的函数


export function loadCompanyJobs(user) {

    return new Promise((resolve, reject) => {

        let companyJobs = [];

        db.collection("company").doc(user.selectedCompany).collection("jobs").get().then((jobs) => {


            jobs.forEach((job) => {

                loadJobLinkedServices(user, job).then((jobLinkedServices) => {

                    companyJobs.push({
                        id:     job.id,
                        ...

                    });
                });

            });

            resolve(companyJobs);

        }).catch(function (error) {

            ...
        });
    });
}

检索所有集合的子集合的函数

export function loadJobLinkedServices(user, job){

    return new Promise((resolve, reject) => {

        let jobLinkedServices = [];
        db.collection("company").doc(user.selectedCompany).collection("jobs").doc(job.id).collection("linkedServices").get().then((linkedServices) => {

            linkedServices.forEach((linkedService) => {

                jobLinkedServices.push({

                    id:         linkedService.id,
                    ...
                });

            });

            resolve(jobLinkedServices)

        }).catch(function (error) {

            ...
        });
    })

【问题讨论】:

    标签: reactjs firebase redux google-cloud-firestore


    【解决方案1】:

    当你这样做时

    return new Promise((resolve, reject) => {
    
        let companyJobs = [];
    
        db.collection("company").doc(user.selectedCompany).collection("jobs").get().then((jobs) => {
    
    
            jobs.forEach((job) => {
    
                loadJobLinkedServices(user, job).then((jobLinkedServices) => {
    
                    companyJobs.push({
                        id:     job.id,
                        ...
    
                    });
                });
    
            });
    
            resolve(companyJobs);
    
        }).catch(function (error) {
    
            ...
        });
    });
    

    没有什么可以确保您的 Promise 只有在 jobs.forEach() 循环中触发的所有查询都完成后才能解决(即,对 loadJobLinkedServices 函数的调用返回的 Promise 已解决)。

    我不知道 reactjs,但我认为您可以使用 JavaScript Promise.all() 方法,如下所示:

    return new Promise((resolve, reject) => {
    
    
        let promises = [];
    
        let companyJobs = [];
    
        db.collection("company").doc(user.selectedCompany).collection("jobs").get().then((jobs) => {
    
    
            jobs.forEach((job) => {
    
                promises.push(loadJobLinkedServices(user, job));
    
            });
    
            Promise.all(promises).
            then(results => {
              //Loop over the results array to populate the companyJobs array
               resolve(companyJobs);
            })
    
        }).catch(function (error) {
    
            ...
        });
    });
    

    另外,不要忘记正确地将您的调用链接到不同的异步函数,例如:

    query Collection A
    THEN query Collection B
    THEN query all sub-collections (with Promise.all())
    THEN query Collection C
    THEN set Loading Status Inactive
    

    最后,最后一句话:注意get() 方法返回一个promise,所以我不确定你是否需要将对get() 方法的调用包装成一些新的Promises(同样,我不是精通reactjs,所以这句话可能有误)。

    换句话说,我认为您可以执行以下操作(例如对于loadJobLinkedServices 函数):

    export function loadJobLinkedServices(user, job){
    
             let jobLinkedServices = [];
             return db.collection("company").doc(user.selectedCompany).collection("jobs").doc(job.id).collection("linkedServices").get()
            .then((linkedServices) => {
    
                linkedServices.forEach((linkedService) => {
    
                    jobLinkedServices.push({
    
                        id:         linkedService.id,
                        ...
                    });
    
                });
    
                return jobLinkedServices;
    
            }).catch(function (error) {
    
                ...
            });
        })
    

    【讨论】:

    • 感谢您的第一个解决方案。问题是!也感谢您的链接建议。我已经用 PromiseAll 完成了。另外,谢谢你最后的建议,我试试看
    猜你喜欢
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 2015-07-13
    相关资源
    最近更新 更多