Redux可观察到的史诗链调度重复动作

Ale*_*lex 3 redux redux-observable angular

传说

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

目标

我需要将数据发送到服务器。我有一个CREATECREATE_SUCCESSCREATE_FAIL行动。我的想法是CREATE在提交时发送。然后,我有一个action-chain epic,它开始service调用我的服务器并触发CREATE_SUCCESSCREATE_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)
                        })
                })
        }
    }
Run Code Online (Sandbox Code Playgroud)

这就是我撰写的内容,并且大部分都在起作用。如果有更好的方法,我全神贯注。直到最近,分派多个动作才不是真正的问题,但是对我来说似乎从来没有问题,所以我很乐意修复它。

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

编辑2:没关系编辑。这是一个孤立的情况,submit事件一直冒泡到顶部,并且因为我将@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
})
Run Code Online (Sandbox Code Playgroud)

此代码调度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
})
Run Code Online (Sandbox Code Playgroud)

此代码似乎正常工作,并且仅触发每个动作之一。我对为什么这样工作感到非常困惑。根据API文档,此属性装饰一个动作创建者函数,并分派其返回值(一个动作对象)。这很奇怪,因为我打电话来CREATECREATE_SUCCESS一样。这个装饰器如何工作?

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

解决方案

在jayphelps的帮助下。感谢您的答复。但是,我喜欢在@dispatch组件内部使用的装饰。我发现的个人解决方案是以starter-actions不通过Epic调度(从组件内部调度的)的方式构建动作链。然后只需用装饰它们starter-actions@dispatch它就可以工作。

jay*_*lps 5

提供的代码很好;看到这里,只有一个CREATE_SUCCESShttps : //jsbin.com/tagovok/edit?js,输出

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

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

根据您的更新:

我将行为的范围缩小到:如果我从Epic中调用一个动作,并且该动作以@dispatch()装饰,它将被触发两次。我怀疑作为中间件的Epic在内部调度收到的操作。问题来了,如果我需要从我的容器组件中手动调度一个动作。

实际上,redux-observable会自动调度您的Epics发出的动作。我没有使用angular-redux的经验,但是这里有一些关于将其与redux-observable结合使用的文档:https : //github.com/angular-redux/store/blob/master/articles/epics.md

快速浏览一下,表明他们不使用史诗中的动作创建者,而只是使用POJO。您仍然可以创建仅返回POJO动作(仅正常redux)的动作创建者。