如何等待承诺广告将数据推送到forEach循环中的数组[反应]

时间:2019-10-21 09:31:35

标签: javascript reactjs firebase promise google-cloud-firestore

所以我想使用这种效果:

useEffect(() => {
    return db.collection('users').orderBy('lastName').onSnapshot(snap => {
       const usersArray = []
       snap.forEach( async doc => {
         const user = doc.data()
         if(user.manager) {
            await Promise.all([
            db.collection('users').doc(user.manager).get(),
            db.collection('roles').doc(user.profile).get()
          ]).then(resp => {
                    const manager = resp[0].data()
                    const role = resp[1].data()
                    usersArray.push({
                      id: doc.id,
                      ...user,
                      manager: `${manager.lastName} ${manager.name} ${manager.middleName}`,
                      role: role.profile
                    })
                  })
         } else {
           await db
             .collection('roles')
             .doc(user.profile)
             .get().then(resp => {
              const role = resp.data()
              usersArray.push({
                id: doc.id,
                ...user,
                role: role.profile
              })
             })
         }
         usersArray.push({test: 'test'})
       })
       console.log(usersArray)
       setAgents(usersArray)
     })
   }, [])

这里我要获取用户列表,然后我想为每个用户获取有关他们在系统中及其管理者角色的数据,并更新用户对象并推送到数组。之后,我要渲染它。但是现在,我总是得到空数组。在console.log的{​​{1}}中,数据是正确的。

请帮助获取正确的代码

enter image description here

1 个答案:

答案 0 :(得分:1)

这是因为代码的console.log部分是在将任何数据实际写入数组之前同步执行的。 forEach数组属性创建一个与主执行无关的非阻塞回调。如果要确保在执行snap之前处理console.log中的每个项目,我建议改用map,则map具有一个唯一的属性,它实际上返回一个值(与foreach相反) )。在这种情况下,返回值将是回调承诺。您可以等待地图的结果,以确保所有项目都已写入数组,甚至最好在回调内部返回实际项目。

这是示例代码(为简单起见,我删除了我认为不需要的usersArray.push({test: 'test'})

useEffect(() => {
    return db.collection('users').orderBy('lastName').onSnapshot(snap => {
        const usersArrayPromise = snap.documents.map(doc => {
            const user = doc.data();

            if (user.manager) return Promise.all([
                db.collection('users').doc(user.manager).get(),
                db.collection('roles').doc(user.profile).get()
            ]).then(resp => {
                const manager = resp[0].data();
                const role = resp[1].data();
                return {id: doc.id, ...user, manager: `${manager.lastName} ${manager.name} ${manager.middleName}`, role: role.profile};
            });

            return db.collection('roles')
                .doc(user.profile)
                .get().then(resp => {
                    const role = resp.data();
                    return {id: doc.id, ...user, role: role.profile}
                })
        });
        Promise.all(usersArrayPromise).then(usersArray => {
            console.log(usersArray)
            setAgents(usersArray)
        });
    })
}, []);

请注意以下事实:firebase QuerySnapshot不是实际的数组,而是实现了forEach属性之类的数组,如果要使用map,则可以执行snap.documents.map