在 Redux 中我应该在哪里编写复杂的异步流?

Posted

技术标签:

【中文标题】在 Redux 中我应该在哪里编写复杂的异步流?【英文标题】:Where should I Compose Complex Asynchronous Flows in Redux? 【发布时间】:2016-09-15 13:58:17 【问题描述】:

我想使用 redux 对以下异步逻辑进行建模:

    用户操作会触发一系列异步 API 调用。 任何 API 调用都可能返回 401 状态(登录超时) 如果 API 响应 401,则显示重新登录弹出窗口 成功重新登录后,重新发出 API 调用并继续

我不知道该把这个逻辑放在哪里。 Actions不知道其他actions,它们只有dispatch的权限,所以不能停下来等待它们完成。 Reducers 无法访问 dispatch,所以我不能把它放在那里……那么它在哪里?自定义中间件?商店听听?在智能组件中?

我目前正在使用 redux-promise-middleware 和 redux-thunk。如何最好地组织这种类型的流程——而不需要购买像 redux-saga 或 redux-rx 之类的东西?

也不确定透明中断 API 调用以执行其他操作的最佳方法,即 API 调用在可选登录过程完成之前不应触发其完成或失败的操作。

【问题讨论】:

【参考方案1】:

在我看来,您需要一个能够生成 Thunk 并将所有逻辑保存在 Thunk 中的动作创建器。确实没有其他好的方法可以保留您的 API 调用套件之间的关联,并确保在其中一个调用失败时取消所有其他调用。

    在那个 Thunk 中,您将触发您的 API 调用,并收集他们的承诺:

    const call1 = promiseGenerator1();
    const call2 = promiseGenerator2();
    const call3 = promiseGenerator3();
    const allCallPromises = [call1, call2, call3];
    

    使用all() 承诺处理程序来监控它们:

    const watcher = Promise.all(allCallPromises).then(allSuccess, anyFail);
    

    您的失败处理程序将:

    如果其中任何一个是 401,则取消其余的承诺。 (注意,这需要像 Bluebird 这样具有取消语义的库,或者对您的承诺/请求进行某种其他形式的增强。)

    调度一个动作或路由更改以触发重新登录窗口

    anyFail(error) => 
        if (error.status === 401) 
            allCallPromises.forEach((item)=> item.cancel(););
            reLogin();
        
    
    

    然后,我倾向于让您的重新登录组件担心再次重新触发相同的复杂操作,以发出所有调用。

    但是,如果您的 API 调用套件是可变的或特定于上下文的,您可以从 anyFail 处理程序内部缓存您需要的那些。有一个减速器,您可以在其中存放actionPendingReLogin。编写一个将重新触发与上次相同的调用的操作,然后调度它:

    dispatch(createAction('CACHE_RELOGIN_ACTION`, actionObjectToSaveForLater));
    

    (或者,只缓存您使用的任何动作创建器。)

    然后,在成功重新登录后,您可以:

    const action = store.getState('actionPendingReLogin');
    dispatch(action);
    // or:
    const actionCreator = store.getState('actionPendingReLogin');
    dispatch(actionCreator());
    

哦:在您的 allSuccess 处理程序中,您只需调度异步调用的结果。

【讨论】:

以上是关于在 Redux 中我应该在哪里编写复杂的异步流?的主要内容,如果未能解决你的问题,请参考以下文章

redux 在哪里处理副作用?

在 redux 中在哪里调度多个操作?

React Native - Redux 不会立即更新

为啥我们需要中间件用于 Redux 中的异步流?

为啥我们需要中间件用于 Redux 中的异步流?

使用 Redux 无法在 componentDidMount 中接收异步响应