redux-observable 史诗链分派重复动作
redux-observable epic chain dispatches duplicate actions
图例
action-chain epic
= Epic,其中 returns 'success' 或 'fail' 动作,基于服务调用。
service
= Http 服务,来自 HttpModule
,Angular2
目标
我需要向服务器发送数据。我有 CREATE
、CREATE_SUCCESS
和 CREATE_FAIL
操作。我的想法是在提交时发送 CREATE
。然后我有一个 action-chain epic
,它开始 service
调用我的服务器并根据响应触发 CREATE_SUCCESS
或 CREATE_FAIL
。
问题
我的 action-chain epic
触发了重复的动作 - 在这两种情况下它都触发了两个动作,例如:如果成功,对于每个 CREATE
它都会调度两个 CREATE_SUCCESS
动作。
密码
private createAnimalActionChain() {
return action$ => {
return action$
.ofType(AnimalActions.CREATE)
.switchMap(action => {
return this.service
.create(action.payload)
.map(httpResponse => {
let response = httpResponse.json()
if (response.success) {
return this.actions.createSuccess()
}
return this.actions.createFail(response.errors)
})
})
}
}
这是我编写的,大部分都有效。如果有更好的方法,我会洗耳恭听。直到最近,分派多个操作才成为真正的问题,但它对我来说似乎从来都不是问题,所以我很乐意修复它。
编辑:我刚刚发现有时我的应用程序会在执行任何 Epic 之前分派重复操作。我现在正试图理解为什么。
编辑 2:没关系 编辑。这是一个孤立的案例,提交事件一直冒泡到顶部,因为我将我的 @Output()
字段命名为 'submit' - 它导致了双重操作调度。它现在已修复,与上述 Epic 问题无关。它仍然存在。
编辑 3:在@jayphelps 的帮助下,我能够跟踪问题。事实证明,我从史诗链中调用的操作触发了两次。我不确定为什么会这样。这是我的旧代码:
static CREATE = 'CREATE'
static CREATE_SUCCESS = 'CREATE_SUCCESS'
static CREATE_FAIL = 'CREATE_FAIL'
@dispatch()
create = (animal: IAnimal) => ({
type: AnimalActions.CREATE,
payload: animal
})
@dispatch()
createSuccess = () => ({
type: AnimalActions.CREATE_SUCCESS
})
@dispatch()
createFail = (errors: object) => ({
type: AnimalActions.CREATE_FAIL,
payload: errors
})
此代码调度 CREATE
一次,CREATE_SUCCESS
两次,CREATE_FAIL
两次。我删除了最后两个 @dispatch()
装饰器:
static CREATE = 'CREATE'
static CREATE_SUCCESS = 'CREATE_SUCCESS'
static CREATE_FAIL = 'CREATE_FAIL'
@dispatch()
create = (animal: IAnimal) => ({
type: AnimalActions.CREATE,
payload: animal
})
createSuccess = () => ({
type: AnimalActions.CREATE_SUCCESS
})
createFail = (errors: object) => ({
type: AnimalActions.CREATE_FAIL,
payload: errors
})
这段代码似乎可以正常工作,并且每个动作只触发一个。我很困惑为什么会这样。根据 API docs,这个 属性 装饰了一个 action-creator 函数并分派它的 return 值,一个动作 object。这很奇怪,因为我调用 CREATE
和 CREATE_SUCCESS
相同。这个装饰器是如何工作的?
编辑 4:
我将行为缩小为:如果我从我的 Epic 中调用一个动作并且这个动作用 @dispatch
装饰,它会被触发两次。我怀疑作为中间件的 Epic 会在内部发送接收到的操作。问题来了,如果我需要从我的容器组件中手动调度一个动作。
解决方法
在 jayphelps 的帮助下。感谢您的答复。但是我喜欢 @dispatch
装饰,用于我的组件内部。我发现的一个个人解决方案是以 starter-actions
(从组件内部调度的那些)不会通过 Epic 调度的方式构建我的动作链。然后用 @dispatch
装饰那些 starter-actions
就可以了。
提供的代码没问题;看到这里,只有一个CREATE_SUCCESS
:https://jsbin.com/tagovok/edit?js,output
这表明问题出在此处未提供的代码中。我能想到的三种直接可能性:
- 在某处,你正在以某种方式调度两个
CREATE
操作(使用 redux devtools 查看)
this.service.create(action.payload)
实际上发出 两个 东西而不是一个(使用 do
、debugger
s,或者你甚至可以只添加一个 .take(1)
在它之后,如果修复它你知道)
- 您将同一史诗添加了两次,例如
combineEpics(yourEpic, yourEpic)
(这个很难确认。也许尝试在 epic it 的初始调用中添加一个计数器并确认它只会递增到 1,因为 epic 函数本身只被调用一次)
根据您的更新:
I have narrowed the behavior down to this: If I call an action from within my Epic and this action is decorated with @dispatch(), it is triggered twice. I suspect that the Epic, being a middleware internally dispatches the received action. The problem comes, if I need to manually dispatch an action from my container component.
确实 redux-observable 会自动调度您的 Epics 发出的操作。我没有使用 angular-redux 的经验,但是这里有一些关于将它与 redux-observable 一起使用的文档:https://github.com/angular-redux/store/blob/master/articles/epics.md
快速浏览一下表明他们不使用 epics 中的动作创建器,而是只使用 POJO。您仍然可以创建仅 return POJO 操作的操作创建器,just normal redux。
图例
action-chain epic
= Epic,其中 returns 'success' 或 'fail' 动作,基于服务调用。
service
= Http 服务,来自 HttpModule
,Angular2
目标
我需要向服务器发送数据。我有 CREATE
、CREATE_SUCCESS
和 CREATE_FAIL
操作。我的想法是在提交时发送 CREATE
。然后我有一个 action-chain epic
,它开始 service
调用我的服务器并根据响应触发 CREATE_SUCCESS
或 CREATE_FAIL
。
问题
我的 action-chain epic
触发了重复的动作 - 在这两种情况下它都触发了两个动作,例如:如果成功,对于每个 CREATE
它都会调度两个 CREATE_SUCCESS
动作。
密码
private createAnimalActionChain() {
return action$ => {
return action$
.ofType(AnimalActions.CREATE)
.switchMap(action => {
return this.service
.create(action.payload)
.map(httpResponse => {
let response = httpResponse.json()
if (response.success) {
return this.actions.createSuccess()
}
return this.actions.createFail(response.errors)
})
})
}
}
这是我编写的,大部分都有效。如果有更好的方法,我会洗耳恭听。直到最近,分派多个操作才成为真正的问题,但它对我来说似乎从来都不是问题,所以我很乐意修复它。
编辑:我刚刚发现有时我的应用程序会在执行任何 Epic 之前分派重复操作。我现在正试图理解为什么。
编辑 2:没关系 编辑。这是一个孤立的案例,提交事件一直冒泡到顶部,因为我将我的 @Output()
字段命名为 'submit' - 它导致了双重操作调度。它现在已修复,与上述 Epic 问题无关。它仍然存在。
编辑 3:在@jayphelps 的帮助下,我能够跟踪问题。事实证明,我从史诗链中调用的操作触发了两次。我不确定为什么会这样。这是我的旧代码:
static CREATE = 'CREATE'
static CREATE_SUCCESS = 'CREATE_SUCCESS'
static CREATE_FAIL = 'CREATE_FAIL'
@dispatch()
create = (animal: IAnimal) => ({
type: AnimalActions.CREATE,
payload: animal
})
@dispatch()
createSuccess = () => ({
type: AnimalActions.CREATE_SUCCESS
})
@dispatch()
createFail = (errors: object) => ({
type: AnimalActions.CREATE_FAIL,
payload: errors
})
此代码调度 CREATE
一次,CREATE_SUCCESS
两次,CREATE_FAIL
两次。我删除了最后两个 @dispatch()
装饰器:
static CREATE = 'CREATE'
static CREATE_SUCCESS = 'CREATE_SUCCESS'
static CREATE_FAIL = 'CREATE_FAIL'
@dispatch()
create = (animal: IAnimal) => ({
type: AnimalActions.CREATE,
payload: animal
})
createSuccess = () => ({
type: AnimalActions.CREATE_SUCCESS
})
createFail = (errors: object) => ({
type: AnimalActions.CREATE_FAIL,
payload: errors
})
这段代码似乎可以正常工作,并且每个动作只触发一个。我很困惑为什么会这样。根据 API docs,这个 属性 装饰了一个 action-creator 函数并分派它的 return 值,一个动作 object。这很奇怪,因为我调用 CREATE
和 CREATE_SUCCESS
相同。这个装饰器是如何工作的?
编辑 4:
我将行为缩小为:如果我从我的 Epic 中调用一个动作并且这个动作用 @dispatch
装饰,它会被触发两次。我怀疑作为中间件的 Epic 会在内部发送接收到的操作。问题来了,如果我需要从我的容器组件中手动调度一个动作。
解决方法
在 jayphelps 的帮助下。感谢您的答复。但是我喜欢 @dispatch
装饰,用于我的组件内部。我发现的一个个人解决方案是以 starter-actions
(从组件内部调度的那些)不会通过 Epic 调度的方式构建我的动作链。然后用 @dispatch
装饰那些 starter-actions
就可以了。
提供的代码没问题;看到这里,只有一个CREATE_SUCCESS
:https://jsbin.com/tagovok/edit?js,output
这表明问题出在此处未提供的代码中。我能想到的三种直接可能性:
- 在某处,你正在以某种方式调度两个
CREATE
操作(使用 redux devtools 查看) this.service.create(action.payload)
实际上发出 两个 东西而不是一个(使用do
、debugger
s,或者你甚至可以只添加一个.take(1)
在它之后,如果修复它你知道)- 您将同一史诗添加了两次,例如
combineEpics(yourEpic, yourEpic)
(这个很难确认。也许尝试在 epic it 的初始调用中添加一个计数器并确认它只会递增到 1,因为 epic 函数本身只被调用一次)
根据您的更新:
I have narrowed the behavior down to this: If I call an action from within my Epic and this action is decorated with @dispatch(), it is triggered twice. I suspect that the Epic, being a middleware internally dispatches the received action. The problem comes, if I need to manually dispatch an action from my container component.
确实 redux-observable 会自动调度您的 Epics 发出的操作。我没有使用 angular-redux 的经验,但是这里有一些关于将它与 redux-observable 一起使用的文档:https://github.com/angular-redux/store/blob/master/articles/epics.md
快速浏览一下表明他们不使用 epics 中的动作创建器,而是只使用 POJO。您仍然可以创建仅 return POJO 操作的操作创建器,just normal redux。