Redux Promise和Redux Promise Middleware有什么意义?

时间:2017-11-21 20:39:16

标签: redux redux-thunk redux-promise redux-promise-middleware

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

当我遇到API调用和异步动作创建者时,我已经设法绕过Redux的机制,但是,我在中间件中遇到了困难的承诺。

你能帮我弄清楚吗?

这个难题的共同点让我头疼:

  1. 其中一个YT教程说本机Redux调度方法不支持从动作创建者返回的promise - 因此需要Redux Promise库(我知道该项目现在可能已经死了,延续是Redux Promise Middleware)

  2. Dan在“What is the difference between redux-thunk and redux-promise?”中说道,即使没有中间件,我也可以使用承诺 - 只需在动作创建者中管理它们。

  3. 在其他答案中,我找到了使用thunks的示例,其中动作创建者返回了... 承诺(后来在调用者/ 调度中处理(myActionCreator(params) 。然后(...) / 因此,一个承诺可以由thunk 没有任何redux-promise lib返回。?

  4. 在“What is the difference between redux-thunk and redux-promise?”中,接受的答案表明Redux Thunk返回函数,而Redux Promise返回promises ...到底是什么?

  5. 总结一下:使用Redux Promise或Redux Promise Middleware有什么意义?为什么Redux本身不支持承诺?

    更新

    我刚才意识到,在上面的第3点中,我忽略了module.exports.blueprints = { /*************************************************************************** * * * Action routes speed up the backend development workflow by * * eliminating the need to manually bind routes. When enabled, GET, POST, * * PUT, and DELETE routes will be generated for every one of a controller's * * actions. * * * * If an `index` action exists, additional naked routes will be created for * * it. Finally, all `actions` blueprints support an optional path * * parameter, `id`, for convenience. * * * * `actions` are enabled by default, and can be OK for production-- * * however, if you'd like to continue to use controller/action autorouting * * in a production deployment, you must take great care not to * * inadvertently expose unsafe/unintentional controller logic to GET * * requests. * * * ***************************************************************************/ // actions: true, /*************************************************************************** * * * RESTful routes (`sails.config.blueprints.rest`) * * * * REST blueprints are the automatically generated routes Sails uses to * * expose a conventional REST API on top of a controller's `find`, * * `create`, `update`, and `destroy` actions. * * * * For example, a BoatController with `rest` enabled generates the * * following routes: * * ::::::::::::::::::::::::::::::::::::::::::::::::::::::: * * GET /boat -> BoatController.find * * GET /boat/:id -> BoatController.findOne * * POST /boat -> BoatController.create * * PUT /boat/:id -> BoatController.update * * DELETE /boat/:id -> BoatController.destroy * * * * `rest` blueprint routes are enabled by default, and are suitable for use * * in a production scenario, as long you take standard security precautions * * (combine w/ policies, etc.) * * * ***************************************************************************/ // rest: true, /*************************************************************************** * * * Shortcut routes are simple helpers to provide access to a * * controller's CRUD methods from your browser's URL bar. When enabled, * * GET, POST, PUT, and DELETE routes will be generated for the * * controller's`find`, `create`, `update`, and `destroy` actions. * * * * `shortcuts` are enabled by default, but should be disabled in * * production. * * * ***************************************************************************/ // shortcuts: true, /*************************************************************************** * * * An optional mount path for all blueprint routes on a controller, * * including `rest`, `actions`, and `shortcuts`. This allows you to take * * advantage of blueprint routing, even if you need to namespace your API * * methods. * * * * (NOTE: This only applies to blueprint autoroutes, not manual routes from * * `sails.config.routes`) * * * ***************************************************************************/ // prefix: '', /*************************************************************************** * * * An optional mount path for all REST blueprint routes on a controller. * * And it do not include `actions` and `shortcuts` routes. * * This allows you to take advantage of REST blueprint routing, * * even if you need to namespace your RESTful API methods * * * ***************************************************************************/ // restPrefix: '', /*************************************************************************** * * * Whether to pluralize controller names in blueprint routes. * * * * (NOTE: This only applies to blueprint autoroutes, not manual routes from * * `sails.config.routes`) * * * * For example, REST blueprints for `FooController` with `pluralize` * * enabled: * * GET /foos/:id? * * POST /foos * * PUT /foos/:id? * * DELETE /foos/:id? * * * ***************************************************************************/ // pluralize: false, /*************************************************************************** * * * Whether the blueprint controllers should populate model fetches with * * data from other models which are linked by associations * * * * If you have a lot of data in one-to-many associations, leaving this on * * may result in very heavy api calls * * * ***************************************************************************/ // populate: true, /**************************************************************************** * * * Whether to run Model.watch() in the find and findOne blueprint actions. * * Can be overridden on a per-model basis. * * * ****************************************************************************/ // autoWatch: true, /**************************************************************************** * * * The default number of records to show in the response from a "find" * * action. Doubles as the default size of populated arrays if populate is * * true. * * * ****************************************************************************/ // defaultLimit: 30 }; 附加then()而不是包含 {{1} } args。

3 个答案:

答案 0 :(得分:4)

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

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

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

如果您尝试传递除普通对象操作之外的任何内容,则商店将抛出错误:

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

Middleware form a pipeline around store.dispatch(),每个中间件都可以使用传递给dispatch modify it, log it, delay it, or dispatch something else instead it的任何值来执行任何操作。这意味着中间件可以教授" dispatch()如何通过拦截价值并做其他事情来接受 普通行动对象的内容。

所以,redux-thunk"教导" dispatch如何接受函数,通过拦截函数并调用它而不是将其传递给reducers。 redux-promise"教授" dispatch如何接受承诺,通过在承诺解决或拒绝时拦截承诺和派遣行动。

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

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

有关该主题的更多信息,请参阅Redux FAQ entry on dealing with side effects以及Redux Side EffectsReact/Redux links list部分中的文章。

答案 1 :(得分:3)

当调用动作创建者(动作创建者功能的第一行)时,您将发出ajax请求。这是一个网络请求,将请求该JSON API。

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

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

因此,在从动作创建者返回动作后,在将来的某个时候,我们会从JSON API返回响应。

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

无论花费多长时间,直到动作显示在减速器内部时,它始终可以从API中获取我们的数据。

为了给您一个更好的主意,我在自己的一个reducers中添加了一个debugger语句,以便我们可以查看其中的不同值。

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

enter image description here

当我单击“获取注释”按钮时,即当它调用动作创建者时,在“源”选项卡中,我立即单击了debugger语句。

有证据表明,每当该动作出现在化简器中时,它就会具有从API获得的响应。

enter image description here

现在,让我们删除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>;
};

这是什么?

enter image description here

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

动作创建者并不是为支持异步请求而开发的,我不知道这是一种疏忽。

我们使用Redux Promise之类的中间件来查看将要发送到reducer的操作,并且我们有机会完全延迟,记录,修改或停止该操作,并且只有通过这些中间件我们才能发出这些异步请求按照我们期望的方式工作。我们使用Redux Promise是因为我们要检查操作创建者返回的每个操作,并且如果它包含API请求或某个异步请求,我们希望将其延迟,因此我们可以使该响应在操作继续进行之前返回。减速器。这就是Redux Promise为我们所做的。

答案 2 :(得分:1)

你需要那些中间件以避免竞争条件,因为javascript是异步的。它们之间的差异只是实现,thunk与函数一起工作,sagas与生成器等等