在React Redux中嵌套API调用

时间:2018-10-29 20:31:13

标签: javascript reactjs redux react-redux

我很难弄清动作创建者中正在发生(而不是未发生)的情况。

我需要调用一个API端点,获取返回的所有项目的ID和名称,然后针对每个ID进行另一个调用。我想将上次调用的返回值和第一次调用的ID /名称存储在一个对象中并进行分派。

{
  category: name //name of category
  subcategory: [] //array of categories in the category above. 
}

现在,我的减速器确实可以满足我的需求,但是当我尝试在组件中记录该特定道具时,它是空的。 (下面我正在使用OpenSocialAPI或osapi。这只是一个ajax请求的基本包装。它使我不必进行身份验证,因为它看到我已被身份验证。)

export function fetchCategories(id){
  let categories = []
  return function(dispatch){
    dispatch(requestCategories(id))
    return osapi.core.get({
      v: "v3",
      href: "/places/" + id + "/places"
    }).execute(function(response) {
      response.content.list.forEach(function(category) {
        osapi.core.get({
          v: "v3",
          href: "/places/" + category.id+ "/categories"
        }).execute(function(response) {
          categories.push({
            category: category.name,
            subcategories: response.content.list.map(category => category.name)
          })
        })
      })

    console.log("Category response: ", categories)
    dispatch(receiveCategories(id, categories))
    })
  }
}
export function receiveCategories(id,array){
  return {
    type: RECEIVE_CATEGORIES,
    id,
    categories: array,
    recievedAt: new Date(Date.now()),
    isFetching: false
  }
}

然后在我的应用中,我在componentDidMount中调度动作创建者

  componentDidMount() {
    const { dispatch } = this.props
    dispatch(fetchCategoriesIfNeeded(id))
  }

现在,当我在我的Category组件和上面的execute中进行控制台登录时,它为空。但是在记录器中查看状态时,recipeCategories完成后,便有了所需的对象数组

[{category:..., 
  subcategories:[...]
 },
 {category:..., 
  subcategories:[...]
 }]

我怀疑这是由于异步原因引起的,但我不确定如何进行。

我试图为基于promise的呼叫创建自己的包装器,但是我遇到了类似的问题,可能还有更多类似的问题,因为我不确定是否要使用resolve(response)。

function httpService(path){
   return new Promise(function(resolve, reject){
          osapi.core.get({
              v: 'v3',
              href: path
          }).execute(function(response, error){
              if(error){
                  return reject(new Error("Error: ", error))
              }
              resolve(response)
          })  
        })
}
export function fetchCategories(spaceId) {
  let categories = []
  return function(dispatch) {
    dispatch(requestCategories(id))
    return httpService("/places/" + id + "/places")
      .then(function(response) {
        response.content.list.forEach(function(category) {
          fetchSubCategories("/places/" + category.id + "/categories")
            .then(function(response) {
              categories.push({
                category: category.name,
                subcategories: response
              })
            })
        })
        console.log("CATEGORIES: ", categories)
        dispatch(receiveCategories(id, categories))
      })
  }
}
function fetchSubCategories(url){
  return httpService(url)
  .then(function(response){
    return response.content.list.map(category => category.name)
  })
}

您可以看一下并提供指导吗?另外,我是否调度基于API响应构建的数组是一种有效的处理方式,还是有更好的方法?谢谢

我只能用相似的用例找到另外一个问题,但是他们使用的是bluebird或类似的东西。我真的很想保留这个,除了Redux。

2 个答案:

答案 0 :(得分:1)

看起来您只需要在.execute()回调的内部 而不是外部分配类别。您正在执行osapi.core.get().execute((response) =>,但随后在该execute回调的外部中,调度了receiveCategories,该操作将在Promise解决之前很长时间执行,然后调度空数组您进行初始化。

您还需要使用Promise.all来获取所有嵌套GET请求的响应。

也没有理由保留变异数组。

答案 1 :(得分:1)

我猜osapi.core.get是某种基于诺言的提取库?而.execute会在获取成功时被调用吗?

如果是这样,那么您所缺少的就是您没有等待所有异步调用完成。

我将展示基于通用fetch和本机Promises的解决方案,以便您了解该解决方案并根据您的特定库采用它。

const promises = [];
response.content.list.forEach(function(category) {
    const promise = fetch("/places/" + category.id+ "/categories");
    promises.push(promise);
})

Promise.all(promises).then(responses => {        
    categories = responses.map(response => ({/* do your object mapping here */}))
    // now you can dispatch with all received categories
    dispatch(receiveCategories(id, categories))
}); 

此外,您在嵌套函数中使用了相同的变量-尽管这可以工作并且计算机可以理解它,但对于任何人来说,弄清楚哪个response属于哪个范围都非常困难。因此,您可能还想再看看一下变量名。