8

我搜索了高低,但找不到明确的答案。

我已经设法绕开 Redux 的机制,但是当我谈到 API 调用和异步操作创建者时,我被 Promises 上下文中的中间件所困。

你能帮我把乱七八糟的东西弄好吗?

难题的相互矛盾的部分让我头疼:

  1. YT 教程之一说,原生 Redux 调度方法不支持从动作创建者返回的承诺——因此需要 Redux Promise 库(我知道该项目现在可能已经死了,延续是 Redux Promise 中间件)。

  2. Dan 在“ redux-thunk 和 redux-promise 有什么区别? ”中说,即使没有中间件,我也可以使用 Promise——只需在动作创建器中管理它们。

  3. 在其他答案中,我发现了使用 thunk 的示例,其中动作创建者返回了一个......承诺(后来在调用者/调度(myActionCreator(params).then(...)中处理) /所以一个承诺可以由一个返回thunk没有任何 redux-promise 库..?

  4. 在“ redux-thunk 和 redux-promise 之间有什么区别? ”中,接受的答案是 Redux Thunk 返回函数,而 Redux Promise 返回 promises.. 到底是什么?

总结一下:使用 Redux Promise 或 Redux Promise 中间件有什么意义?为什么 Redux 本身不支持 Promise?

更新:

我刚刚意识到,在上面的第 3 点中,我忽略了then()附加dispatch而不包含dispatch()args 中。

4

3 回答 3

15

链接的答案是正确的,但我会尝试进一步解释。

一个基本的 Redux 存储将接受调度普通对象操作:

store.dispatch({type : "ADD_TODO", text : "Buy milk"});

如果您尝试传递普通对象操作以外的任何内容,存储将抛出错误:

store.dispatch(() => {});
// Error: "Actions must be plain objects. Use custom middleware for async actions."

中间件形成了一个管道store.dispatch(),每个中间件都可以用传递给它的任何值做任何它想做的事情dispatch修改它、记录它、延迟它或调度其他东西来代替它。这意味着中间件可以通过截取值并执行其他操作来“教”dispatch()如何接受不是普通操作对象的内容。

因此,redux-thunk“教”dispatch如何接受函数,方法是拦截函数并调用它,而不是将其传递给减速器。 redux-promise“教”dispatch如何接受 Promise,方法是在 Promise 解决或拒绝时拦截 Promise 和调度动作。

通常,dispatch返回传入的任何动作对象。因为中间件环绕dispatch,它们还可以更改返回的值。 redux-thunk将运行 thunk 函数,并返回 thunk 函数返回的任何内容。这让你可以做一些有用的事情,比如从一个 thunk 中返回一个 Promise,并从那里链接行为:

dispatch(someThunkReturningAPromise())
    .then(() => {
        // Do more stuff here
    });

有关该主题的更多信息,请参阅有关处理副作用的 Redux 常见问题解答条目,以及我的React/Redux 链接列表的Redux 副作用部分中的文章。

于 2017-11-22T16:57:16.953 回答
5

当您调用动作创建者(动作创建者函数的第一行之一)时,您会发出 ajax 请求。那是一个网络请求,它将到达那个 JSON API。

要理解的关键部分是,当我们发出请求时,我们会进入下一行代码,在其中形成该操作对象并返回它。这两个步骤之间的时间,即发出请求和返回操作之间的时间是瞬时的。

众所周知,每当我们向某个外部 API 发出网络请求时,可能需要一些时间才能得到响应。

因此,在我们从动作创建者返回动作之后,在未来的某个时间,我们会从 JSON API 获得响应。

因此,在发出 Ajax 请求和从动作创建者返回的动作之间可能是瞬时的,但是从动作创建者返回的动作和收到来自 JSON API 的响应之间的时间可能需要更长的时间。

无论花费多长时间,当 action 出现在 reducer 中时,它总是可以从我们的 API 中获得我们的数据。

为了给你一个更好的主意,我debugger在我自己的一个 reducer 中添加了一个语句,这样我们就可以查看其中的不同值。

import { SAVE_COMMENT, FETCH_COMMENTS } from 'actions/types';

export default function(state = [], action) {
  switch (action.type) {
    case SAVE_COMMENT:
      return [...state, action.payload];
    case FETCH_COMMENTS:
      debugger;
      const comments = action.payload.data.map(comment => comment.name);
      return [...state, ...comments];
    default:
      return state;
  }
}

在此处输入图像描述

当我单击 Fetch Comments 按钮时,它调用了动作创建者,在我的源选项卡中,我立即点击了该debugger语句。

这里有证据表明,每当这个动作出现在 reducer 中时,它都有从 API 获得的响应。

在此处输入图像描述

现在,让我们移除 Redux Promise 中间件,看看会发生什么。

中间件:

export default ({ children, initialState = {} }) => {
  const store = createStore(
    reducers,
    initialState,
    applyMiddleware(reduxPromise)
  );

中间件不见了:

export default ({ children, initialState = {} }) => {
  const store = createStore(reducers, initialState, applyMiddleware());

  return <Provider store={store}>{children}</Provider>;
};

这是什么?

在此处输入图像描述

payload不是从 JSON API 返回的响应,而是一个 pending ,Promise这意味着我们的请求仍在网络上等待从 JSON API 返回。很明显,如果没有 Redux Promise 中间件,我们的应用程序将无法按预期工作。

动作创建者不是为了支持异步请求而开发的,称之为疏忽,我不知道。

我们使用像 Redux Promise 这样的中间件来查看即将发送到 reducer 的操作,我们有机会完全延迟、记录、修改或停止操作,并且只有通过这些中间件,我们才能使这些异步请求以这种方式工作我们期望它。我们使用 Redux Promise 是因为我们想要检查从动作创建者返回的每个动作,如果它包含 API 请求或一些异步请求,我们想要延迟它,这样我们就可以在动作继续之前得到响应返回减速机。这就是 Redux Promise 为我们所做的。

于 2019-01-30T23:26:21.633 回答
1

您需要这些中间件以避免竞争条件,因为 javascript 是异步的。它们之间的区别只是实现,thunk 与函数一起使用,sagas 与生成器等

于 2018-04-22T00:57:42.407 回答