React-redux项目 - 链接的依赖异步调用不能与redux-promise中间件一起使用?

时间:2018-01-20 06:58:59

标签: redux react-redux redux-promise

我是使用redux的新手,我正在尝试将redux-promise设置为中间件。我有这种情况我似乎无法开始工作(当我只是尝试在没有链接的情况下进行一次异步调用时,事情对我有用)

假设我有两个API调用:

1) getItem(someId) -> {attr1: something, attr2: something, tagIds: [...]}
2) getTags() -> [{someTagObject1}, {someTagObject2}]

我需要调用第一个,获取一个项目,然后获取所有标签,然后返回一个包含项目和与该项目相关的标签的对象。

现在,我的动作创建者是这样的:

export function fetchTagsForItem(id = null, params = new Map()) {
    return {
        type: FETCH_ITEM_INFO,
        payload: getItem(...) // some axios call
            .then(item => getTags() // gets all tags 
                .then(tags => toItemDetails(tags.data, item.data)))
    }
}

我在toItemDetails中有一个console.log,我可以看到,当调用完成后,我们最终会进入toItemDetails并得到正确的信息。但是,看起来我们在调用完成之前就已经开始使用reducer了,而我只是从reducer中获取了一个未定义的有效负载(并且它不再尝试)。 reducer只是试图为这种情况返回action.payload。

我知道链接的电话不是很好,但我至少希望看到它有效。这可以通过redux-promise来完成吗?如果没有,将非常感谢任何如何实现这一功能的例子!

1 个答案:

答案 0 :(得分:0)

我使用占位符函数填充了您丢失的代码,它对我有用 - 我的有效负载最终包含一个解析为toItemDetails的返回值的promise。也许这可能是你在这里没有包含的代码中的东西。

function getItem(id) {
  return Promise.resolve({
    attr1: 'hello',
    data: 'data inside item',
    tagIds: [1, 3, 5]
  });
}

function getTags(tagIds) {
  return Promise.resolve({ data: 'abc' });
}

function toItemDetails(tagData, itemData) {
  return { itemDetails: { tagData, itemData } };
}

function fetchTagsForItem(id = null) {
  let itemFromAxios;
  return {
    type: 'FETCH_ITEM_INFO',
    payload: getItem(id)
      .then(item => {
        itemFromAxios = item;
        return getTags(item.tagIds);
      })
      .then(tags => toItemDetails(tags.data, itemFromAxios.data))
  };
}


const action = fetchTagsForItem(1);
action.payload.then(result => {
  console.log(`result:  ${JSON.stringify(result)}`);
});

输出:

result:  {"itemDetails":{"tagData":"abc","itemData":"data inside item"}}

为了在第二步中访问item,您需要将其存储在fetchTagsForItem的函数范围内声明的变量中,因为这两个.then } s本质上是兄弟姐妹:两者都可以访问封闭范围,但第二次调用.then无法访问第一个声明的变量。

关注点分离

创建发送给Redux的操作的代码也会进行多个Axios调用并按摩返回的数据。这使得阅读和理解变得更加复杂,并且会使处理Axios调用中的错误变得更加困难。我建议拆分。一种选择:

  • 将任何调用Axios的代码放入其自己的函数中
  • payload设置为该函数的返回值。
  • 将该函数以及调用Axios的所有其他函数移动到单独的文件(或文件集)中。该文件将成为您的API客户端。

这看起来像是:

// apiclient.js
const BASE_URL = 'https://yourapiserver.com/';
const makeUrl = (relativeUrl) => BASE_URL + relativeUrl; 
function getItemById(id) {
  return axios.get(makeUrl(GET_ITEM_URL) + id);
}

function fetchTagsForItemWithId(id) {
...
}

// Other client calls and helper funcs here

export default {
  fetchTagsForItemWithId
};

您的行动档案:

// items-actions.js
import ApiClient from './api-client';
function fetchItemTags(id) {
  const itemInfoPromise = ApiClient.fetchTagsForItemWithId(id);
  return {
    type: 'FETCH_ITEM_INFO',
    payload: itemInfoPromise 
  };
}