首页 > 解决方案 > 同步填充/修改数组并在 Promise 中返回修改后的数组

问题描述

我对 ReactJS 和 redux 还很陌生,所以我以前从来没有真正使用过这个。我正在从我的项目中的 API 调用中检索数据。我想通过向对象添加新属性来修改数据。但是,因为代码不是同步运行的,所以返回的是未修改的数组(我假设)而不是修改的数组。

export function loadThings() {
  return dispatch => {
    return dispatch({
     type: 'LOAD_THINGS',
     payload: {
       request: {
         url: API_GET_THINGS_ENDPOINT,
         method: 'GET'
       }
     }
    }).then(response => {
      let things = response.payload.data;
      // Retrieve all items for the loaded "things"
      if(things) {
        things.forEach((thing, thingIndex) => {
            things[thingIndex].items = []
            if (thing.hasOwnProperty('channels') && thing.channels) {
              thing.channels.forEach(channel => {
                if (channel.hasOwnProperty('linkedItems') && channel.linkedItems) {
                  channel.linkedItems.forEach(itemName => {
                    dispatch(loadItems(itemName)).then(
                      item => things[thingIndex].items.push(item) // push the items inside the "things"
                    )
                  })
                }
              })
            }
        })
      }
      things.forEach(data => console.log(data.items.length, data.items)) // data.items.length returns 0, data.items returns a populated array
      return things // return the modified array
    }).catch(error => {
      //todo: handle error
      return false
    })
  }
}

如您所见,我执行了一个 API 调用,它返回名为response. 该数组填充了所有“事物”。如果things存在,我想加载名为“项目”的额外信息。根据 things 数组中的信息,我将执行另一个 API 调用(通过调度loadItems函数完成),该调用返回另一个promise. 根据该 API 调用结果中的数据,我将推入对象的items属性(它是一个数组)things

正如您在评论中看到的那样,如果我遍历things数组并记录items我刚刚创建的属性,它基本上返回 0 作为长度,这意味着在修改数组things之前返回things数组。

我想知道两件事:

请注意:这个函数loadThings()也返回一个 promise(如果你不熟悉 redux)。

您可能有兴趣了解我尝试自己修复代码的方法

由于我无法理解代码异步运行的逻辑,因此我一直在尝试无望的东西。例如将代码包装在另一个中Promise.all并在该承诺中返回修改后的数组。我使用该then承诺的方法来修改things数组,结果完全相同。可能是因为return things正在执行之外promise

我真的很想知道发生了什么

编辑 我已loadItems()按要求将代码添加到问题中:

export function loadItems(itemName) {
  return dispatch => {
    const url = itemName ? API_GET_ITEMS_ENDPOINT + `/${itemName}` : API_GET_ITEMS_ENDPOINT;
    return dispatch({
      type: 'LOAD_ITEMS',
      payload: {
        request: {
          url: url,
          method: 'GET'
        }
      }
    }).then(response => {
      return response.payload.data
    })
  }
}

标签: javascriptreactjspromisesynchronous

解决方案


我的方法是 map over things,为包裹在 a 中的所有项目创建 promise 数组,从而为您提供'sPromise.all数组。Promise.all

然后你things在另一个Promise.all和下一个 then 块中返回这个 promise 数组,你可以thing使用一个简单的 for 循环将数组分配给每个数组:

export function loadThings() {
  return dispatch => {
    return dispatch({
      type: 'LOAD_THINGS',
      payload: {
        request: {
          url: API_GET_THINGS_ENDPOINT,
          method: 'GET'
        }
      }
    }).then(response => {
      let things = response.payload.data;
      // Retrieve all items for the loaded "things"
      const items = things.map((thing) => {
        const thingItems = []
        if (thing.hasOwnProperty('channels') && thing.channels) {
          thing.channels.forEach(channel => {
            if (channel.hasOwnProperty('linkedItems') && channel.linkedItems) {
              channel.linkedItems.forEach(itemName => {
                thingItems.push(dispatch(loadItems(itemName)));
              });
            }
          });
        }

        return Promise.all(thingItems);
      });

      return Promise.all([things, Promise.all(items)])
    })
    .then(([things, thingItems]) => {
      things.forEach((thing, index) => {
        thing.items = thingItems[index];
      })

      return things;
    })
    .catch(error => {
      //todo: handle error
      return false
    })
  }
}

编辑:您需要将dispatch(loadItmes(itemName))呼叫直接推送到thingItems.


推荐阅读