Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在React-Redux中嵌套API调用_Javascript_Reactjs_Redux_React Redux - Fatal编程技术网

Javascript 在React-Redux中嵌套API调用

Javascript 在React-Redux中嵌套API调用,javascript,reactjs,redux,react-redux,Javascript,Reactjs,Redux,React Redux,我很难弄清楚在我的动作创造者身上发生了什么(和没有发生什么) 我需要对一个API端点进行调用,获取返回的所有项的ID和名称,然后对每个ID进行另一个调用。我想将最后一次调用的返回和第一次调用的ID/名称存储在一个对象中,并分派它 { category: name //name of category subcategory: [] //array of categories in the category above. } 现在,我的reducer确实得到了我想要的东西,但是当我尝试

我很难弄清楚在我的动作创造者身上发生了什么(和没有发生什么)

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

{
  category: name //name of category
  subcategory: [] //array of categories in the category above. 
}
现在,我的reducer确实得到了我想要的东西,但是当我尝试在组件中记录特定的道具时,它是空的。(下面我使用的是OpenSocialAPI或osapi。这只是ajax请求的基本包装。允许我不必进行身份验证,因为它认为我已经通过了身份验证。)

在我的应用程序中,我在componentDidMount中调度动作创建者

  componentDidMount() {
    const { dispatch } = this.props
    dispatch(fetchCategoriesIfNeeded(id))
  }
现在,当我登录到我的分类组件和上面的execute中时,它是空的。但是看看我在记录器中的状态,当ReceiveCategories完成时,我就有了我想要的对象数组

[{category:..., 
  subcategories:[...]
 },
 {category:..., 
  subcategories:[...]
 }]
我怀疑这是因为异步的原因,但我不确定如何继续

我试图为基于承诺的调用创建自己的包装器,但我遇到了类似的问题,可能更严重,因为我不确定解决(响应)是否是我想要的

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响应构建的数组是一种有效的方法,还是有更好的方法?多谢各位


我只能找到另外一个类似用例的问题,但他们使用的是蓝鸟或类似的东西。我真的很想保留这个,除了Redux之外没有任何额外的东西

看起来您只需要在
.execute()
回调中分派类别,而不是在回调之外。您正在执行
osapi.core.get()

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


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

我猜
osapi.core.get
是一种基于承诺的获取库,并且
在获取成功时调用

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

我将展示一个基于泛型
fetch
和本机承诺的解决方案,这样您就可以理解该解决方案,并根据您的特定库采用它

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))
}); 

此外,您在嵌套函数中使用了相同的变量-虽然这可能会起作用,计算机可能会理解它,但这使得任何人都很难确定哪个
响应
属于哪个范围。因此,您可能还想再看一看您的变量名。

您使用的是redux thunk,对吗?是的,我使用的是redux thunk。我的道具映射正确,因为我正在修改一个动作,该动作以前只查看一层类别,现在需要更深入地查看。您正在使用的这个获取库是什么?如果不查看
.execute()的内容,很难为正确的修复编写代码
API is..execute只是osapi的.then。如果可能的话,你应该切换到redux sagaInteresting。让另一组眼睛看事情总是很好的。我在最外层执行调度。因为它在循环中,调度自然运行第一个响应的长度。我能简单地将Promise.all包装在secon周围吗d osapi.core.get()?另外,您提到没有保留一个变异数组,您是指类别数组?您建议在末尾删除它吗?或者用另一种方法来构建缩减器数组,而不是定义一个?Promise.all接受一个Promise数组,并行运行它们,并返回一个包含所有值的数组。您不需要使用
forEach
and
push
,只需将最终结果作为
map
返回到所需的数据结构即可。谢谢!我将查看并尝试一下。从execute()api很难判断,您可能需要“promisify”它以使其与promise配合良好。所有这些,就像制作一个正确调用resolve()或reject()的promise包装器一样遵循标准的promise api,不是一个国产的promise api能够用promise实现这一点。所有!学习起来很有趣!我必须使用数组变量来存储承诺。谢谢!是的,当它成功时调用execute。谢谢你写出来!我会看看这个和promise。所有提到的。另外,我更改了所以,就因为他们很敏感,谢谢你让我保持诚实!我会在一点时间后汇报事情的进展。酷!如果答案对你有帮助,别忘了投票。
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))
});