如何确保在执行下一个史诗之前完成一个史诗?
How to make sure one epic is completed before executing the next epic?
这是我们升级到版本 1.x
后在我们的应用程序中遇到的问题,他们在当前堆栈完成后 (https://github.com/redux-observable/redux-observable/pull/493) 引入了调度 epic 的排队操作。
想象一个动作 (INIT_STUFF
),它有一个史诗,其中 return 是一个动作列表(按 INIT_A
、INIT_B
的顺序)。这些行动中的每一个都有自己的史诗。他们在那里做了一些事情,return 一个修改商店的动作。
在 redux-observable 的先前版本中,INIT_B
的史诗可能依赖于 INIT_A
的史诗已完成执行并对商店进行更改这一事实。然后这部史诗可以使用更新后的商店。
在最新版本中,INIT_A
和 INIT_B
的 epics 都按各自的顺序执行,但是它们 return 的操作(即修改商店)被推迟到最后一个史诗完成。这意味着 INIT_B
的史诗无法访问 INIT_A
所做的商店更新。
下面是我所说内容的简单实现:https://redux-observable-playground-ip3qfb.stackblitz.io
对于这样的用例,迁移路径可能是什么?
这个确实有难度。就我个人而言,我认为有两个 epics 需要依赖这样的东西将是一个 anti-pattern,特别是因为它们都是同步的。我认为这不仅仅是因为它是人为设计的,否则我认为你不会遇到这个问题。
如果史诗 B 确实应该等到史诗 A 准备就绪后才开始,那么 parent (initializeStuffEpic) 应该确保执行此序列,或者史诗 B 可以监听一些信号以了解 A 已准备就绪因为 Epics “不应该”像这样泄露它们的实现细节。或者,这可能表明逻辑不应该是两个独立的 Epics 而只是一个,使用函数组合来保持组织有序。
Epics 通常将动作作为信号响应,尽管第二个参数 state$
也是一个 Observable,也可以订阅。如果你真的喜欢这样做,我认为这可能是最简单的方法:
https://stackblitz.com/edit/redux-observable-playground-g1nuis?file=initialize.js
export const initBEpic = (action$, state$) =>
action$.pipe(
ofType("INITIALIZE_B"),
mergeMap(({ payload }) => {
return state$.pipe(
filter(state => state.initialized.A), // Wait until it is indeed true
take(1), // Very important!
map(() => ({
type: "IS_B_READY",
payload: true
}))
);
})
);
与大多数事情一样,有一些注意事项。如果 A 从未准备好怎么办?
--
在 redux-observable v1.0 中对操作的安排方式所做的更改旨在使某些事情更加直观,同时阻止其他一些不良模式。在那个决定中没有考虑这个特定的模式,所以我不完全确定我是否会改变行为以使您的用例更容易。不幸的是,虽然这看起来很明显是行不通的,但这可能是一个可以接受的权衡,因为这是我第一次看到这个。
将 Epics 几乎视为独立的进程(尽管它们不是。)在没有实际信号(动作或状态 $ 更新。)
我们总是有机会为 v2 更改它,但是需要有人针对特定更改提出建议或 PR,而调度的工作方式——QueueScheduler 的内部实例——有点复杂。
这是我们升级到版本 1.x
后在我们的应用程序中遇到的问题,他们在当前堆栈完成后 (https://github.com/redux-observable/redux-observable/pull/493) 引入了调度 epic 的排队操作。
想象一个动作 (INIT_STUFF
),它有一个史诗,其中 return 是一个动作列表(按 INIT_A
、INIT_B
的顺序)。这些行动中的每一个都有自己的史诗。他们在那里做了一些事情,return 一个修改商店的动作。
在 redux-observable 的先前版本中,INIT_B
的史诗可能依赖于 INIT_A
的史诗已完成执行并对商店进行更改这一事实。然后这部史诗可以使用更新后的商店。
在最新版本中,INIT_A
和 INIT_B
的 epics 都按各自的顺序执行,但是它们 return 的操作(即修改商店)被推迟到最后一个史诗完成。这意味着 INIT_B
的史诗无法访问 INIT_A
所做的商店更新。
下面是我所说内容的简单实现:https://redux-observable-playground-ip3qfb.stackblitz.io
对于这样的用例,迁移路径可能是什么?
这个确实有难度。就我个人而言,我认为有两个 epics 需要依赖这样的东西将是一个 anti-pattern,特别是因为它们都是同步的。我认为这不仅仅是因为它是人为设计的,否则我认为你不会遇到这个问题。
如果史诗 B 确实应该等到史诗 A 准备就绪后才开始,那么 parent (initializeStuffEpic) 应该确保执行此序列,或者史诗 B 可以监听一些信号以了解 A 已准备就绪因为 Epics “不应该”像这样泄露它们的实现细节。或者,这可能表明逻辑不应该是两个独立的 Epics 而只是一个,使用函数组合来保持组织有序。
Epics 通常将动作作为信号响应,尽管第二个参数 state$
也是一个 Observable,也可以订阅。如果你真的喜欢这样做,我认为这可能是最简单的方法:
https://stackblitz.com/edit/redux-observable-playground-g1nuis?file=initialize.js
export const initBEpic = (action$, state$) =>
action$.pipe(
ofType("INITIALIZE_B"),
mergeMap(({ payload }) => {
return state$.pipe(
filter(state => state.initialized.A), // Wait until it is indeed true
take(1), // Very important!
map(() => ({
type: "IS_B_READY",
payload: true
}))
);
})
);
与大多数事情一样,有一些注意事项。如果 A 从未准备好怎么办?
--
在 redux-observable v1.0 中对操作的安排方式所做的更改旨在使某些事情更加直观,同时阻止其他一些不良模式。在那个决定中没有考虑这个特定的模式,所以我不完全确定我是否会改变行为以使您的用例更容易。不幸的是,虽然这看起来很明显是行不通的,但这可能是一个可以接受的权衡,因为这是我第一次看到这个。
将 Epics 几乎视为独立的进程(尽管它们不是。)在没有实际信号(动作或状态 $ 更新。)
我们总是有机会为 v2 更改它,但是需要有人针对特定更改提出建议或 PR,而调度的工作方式——QueueScheduler 的内部实例——有点复杂。