javascript - 使用 redux + redux thunk 等待后台任务的惯用方式

标签 javascript reactjs redux react-redux redux-thunk

在我的应用程序中,我们有一个运行时间较长的“配置”任务,该任务异步完成,我们基本上必须使用轮询来检测它是否已完成。为了在发生这种情况时不会阻止用户使用该应用程序,我们在用户交互流程的开始就开始了。但是,在交互流程结束时,用户采取的操作需要等待该供应任务(如果尚未完成)。这里有一种序列图来说明。

[provisioning start][poll for completion....]
[user interactions]      [blocked action....][post provisioning task]

我遇到的问题是想出一种在 Redux 中正确执行此操作的惯用方法。以下是我考虑过的一些事情:

  1. 有一个“请求”reducer,我会在其中存储长期运行的配置任务的 Promise,然后当 [blocked action] 执行时,它只是等待 promise 。这样做的问题是 Redux 特别要求所有存储状态都是可序列化,所以似乎像 Promises 这样的东西在那里不受欢迎。
  2. [blocked action] 操作创建者中订阅商店,并查找表明供应已完成的数据。不幸的是,我非常喜欢的 redux-thunk 不包含对商店的引用,仅包含其 dispatchgetState方法。
  3. 让我的 React 组件在执行 [blocked action] 之前等待配置完成。我不喜欢这样,因为它向我的 View 层添加了太多的 Action 顺序逻辑意识。

由于这些看起来都不是很好的选择,我目前正在使用:

  1. 将配置 Promise 存储在模块属性中,并且基本上执行选项 #1 而无需从商店获取 Promise。我对此并不狂热,因为它会将状态移出 redux 循环,但这似乎是最简单的选择。

是否有更惯用的方法来使用 redux-thunk 实现此目的?如果有另一个异步中间件可以使它更干净,我愿意考虑,尽管我已经在 redux-thunk 上投入了很多。

最佳答案

有几个 redux-promise-middleware 选项可让您分派(dispatch) promise 操作并让中间件使用它们并在 promise 状态更改时发出 PENDING、RESOLVED|REJECTED 操作。如果你正在使用 promises 和 Redux,你可能想看看其中之一。但是,他们不会帮助您解决这个特定问题。

我认为redux-saga是一个非常适合帮助您处理这种情况的中间件。我还没有亲自使用过它,所以我无法提供示例。

另一个可能更简单的选项是 redux-tap .使用点击来显示您的应用程序可以订阅的操作流。让一个被阻止的 Action 创建者订阅该流并等待表示 promise 已完成的 Action (当然应该首先通过 getState 检查商店的内容以查看 promise 是否在此之前完成被阻止的 Action 被调度)。像这样:

// ========= configureStore.js
import ee from 'event-emitter';

// ...
export const actionStream = ee();

// ...
const emitActions = tap(({type} => type, (type, action) => actionStream.emit(type, action);

// install emitActions middleware to run *after* thunk (so that it does not see thunk actions but only primitive actions)


// =========== your action module.js
import {actionStream} from './configureStore';

export function blockedAction(arg) {
    return (dispatch, getState) => {
        if (getState().initDone) {
            return dispatch({type: "blockedAction", payload: arg});
        }

        // wait for init action
        actionStream.once("initAction", initAction => dispatch({type: "blockedAction", payload: arg}));
    };
}

请记住,它不是二进制的“thunk 或 xxx 中间件”选择。您可以加载 thunk 以及许多其他中间件。在一个应用程序中,我使用:

  • 一个 promise 中间件
  • 控制台日志记录中间件
  • 用于批处理更新的自定义中间件
  • 用于将操作持久化到 IndexedDB 的自定义中间件
  • 用于暂停操作流的自定义中间件
  • 防止递归存储通知的中间件

除了 thunk 之外没有任何中间件,这是另一种选择:

选项 5 - 将选项 2 与选项 4 结合起来:将 promise 存储在全局某处。让被阻止的 Action 创建者在分派(dispatch)原始 Action 之前等待 promise 。为了最小化“商店外的状态”,您还可以让 promise 操作将操作发送到商店中以保持商店更新(可能使用 promise 中间件)

关于javascript - 使用 redux + redux thunk 等待后台任务的惯用方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42098523/

相关文章:

javascript - 如何在 AJAX 请求期间将父上下文保存在 CoffeeScript 中

reactjs - 在 Reactjs 中动态生成导航栏?

javascript - 使用 immutable.js 相对于 Object.assign 或扩展运算符的优势

javascript - react-redux 登录后重定向到其他页面

react-native - 在 React Native 中使用 RTK-Query useLazyQuery 时,Jest 无法正确退出

javascript - 如何在 React/Redux 应用程序中刷新页面后保持登录状态

javascript - 在切片中填充 JavaScript 圆

javascript - 用于发送 ajax/JSON 请求的 JQuery 快捷方式

javascript - 为什么在 React 中为一个组件同时创建 index.js 和 Component.js?

javascript - jQuery 下拉列表