检索集合+子集合给我一个空的渲染

时间:2019-06-17 12:36:03

标签: reactjs firebase redux google-cloud-firestore

问题

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

问题在于,即使我使用诺言和加载状态来防止应用程序显示为空,也将使用所有集合数据(具有子集合的集合除外)来呈现应用程序。

过程

- 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) {

            ...
        });
    })

1 个答案:

答案 0 :(得分:2)

完成时

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) {

        ...
    });
});

不能确保仅在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) {

            ...
        });
    })