angular - redux-observable 史诗链分派(dispatch)重复操作

标签 angular redux redux-observable

图例

action-chain epic = Epic,它根据服务调用返回“成功”或“失败”操作。 service = Http服务,来自HttpModule,Angular2

目标

我需要向服务器发送数据。我有一个 CREATECREATE_SUCCESSCREATE_FAIL 操作。我的想法是在提交时分派(dispatch) CREATE。然后我有一个 action-chain epic,它启动对我的服务器的 service 调用并触发 CREATE_SUCCESSCREATE_FAIL,具体取决于关于回应。

问题

我的 action-chain epic 触发了重复的 Action - 在这两种情况下它都触发了两个 Action ,例如:在成功的情况下,对于每个 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)
                        })
                })
        }
    }

这是我编写的,它大部分都在工作。如果有更好的方法,我会洗耳恭听。直到最近,分派(dispatch)多个操作才成为真正的问题,但它对我来说似乎从来都不是问题,所以我很乐意修复它。

编辑:我刚刚发现有时我的应用会在执行任何 Epic 之前分派(dispatch)重复操作。我现在正试图了解原因。

编辑 2:没关系编辑。这是一个孤立的案例,提交事件一直冒泡到顶部,因为我将我的 @Output() 字段命名为“提交”——它导致了双重操作调度。它现在已修复,与上述 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
})

这段代码似乎可以正常工作,并且每个 Action 只触发一个。我很困惑为什么会这样。根据API docs这个属性装饰了一个 Action 创建者函数并分派(dispatch)它的返回值,一个 Action 对象。这很奇怪,因为我相同地调用了 CREATECREATE_SUCCESS。这个装饰器是如何工作的?

编辑 4: 我已经将行为缩小为:如果我从我的 Epic 中调用一个 Action 并且这个 Action 用 @dispatch 装饰,它会被触发两次。我怀疑作为中间件的 Epic 会在内部发送接收到的操作。问题来了,如果我需要从我的容器组件中手动调度一个 Action 。

解决方案

在 jayphelps 的帮助下。感谢您的答复。但是我喜欢 @dispatch 装饰,用于我的组件内部。我发现的一个个人解决方案是以starter-actions(从组件内部调度的那些)不会通过 Epic 调度的方式构建我的 Action 链。然后用 @dispatch 装饰那些 starter-actions 就可以了。

最佳答案

提供的代码没问题;看到这里,只有一个CREATE_SUCCESS: https://jsbin.com/tagovok/edit?js,output

这表明问题出在此处未提供的代码中。我能想到的三种直接可能性:

  • 在某处,您正在以某种方式分派(dispatch)两个 CREATE 操作(使用 redux devtools 查看)
  • this.service.create(action.payload) 实际上发出了两个而不是一个(使用dodebuggers,或者你甚至可以在它后面添加一个 .take(1),如果这样你就知道了)
  • 您将相同的史诗添加了两次,例如combineEpics(yourEpic, yourEpic)(这个很难确认。也许尝试在史诗的初始调用中添加一个计数器并确认它只会递增到 1,因为史诗函数本身只是永远调用一次)

根据您的更新:

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 会自动调度您的 Epic 发出的操作。我没有使用 angular-redux 的经验,但是这里有一些关于将它与 redux-observable 一起使用的文档:https://github.com/angular-redux/store/blob/master/articles/epics.md

快速浏览一下就会发现他们不使用史诗中的 Action 创建器,而是只使用 POJO。您仍然可以创建只返回 POJO 操作的操作创建器,just normal redux .

关于angular - redux-observable 史诗链分派(dispatch)重复操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45648673/

相关文章:

Angular2 等待 $http 响应

javascript - 为什么组件在 this.setState() 完成状态设置之前渲染?

reactjs - 用户使用 redux 登录后需要刷新浏览器才能显示数据

javascript - 使用 Observable.from(<Promise>) 并在 Observable 中捕获错误时如何处理 `UnhandledPromiseRejectionWarning`

javascript - 使用 redux observable 取消请求不起作用

javascript - 是否可以在 Angular 容器微前端中将 Angular JS 作为微前端运行?

javascript - 如何修复 nz-table 删除 Angular 中的无数据显示

angular - Protractor :无法使用 by.deepCss ('input' 选择影子 DOM( polymer )内的输入元素)

javascript - 在组件中作为 prop 访问调度函数

RXJS重复没有机会重复?