Legend
action-chain epic = Epic, which returns 'success' or 'fail' action, based on service call.
service = Http service, from HttpModule, Angular2
The goal
I need to send data to server. I have a CREATE, CREATE_SUCCESS and CREATE_FAIL actions. My idea is to dispatch CREATE on submit. Then I have an action-chain epic, which starts service call to my server and fires CREATE_SUCCESS or CREATE_FAIL depending on the response.
The problem
My action-chain epic fires duplicate actions - in both cases it fires two actions, eg: in case of success, for every CREATE it dispatches two CREATE_SUCCESS actions.
The code
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)
})
})
}
}
This is what I composed and it's working for the most part. If there is a better approach, I am all ears. Dispatching multiple actions was not real problem until recently, but it never seemed ok with me, so I'd love to fix it.
EDIT: I have just found out that sometimes my app dispatches duplicate actions before any Epic is executed. I am now trying to understand why.
EDIT 2: Nevermind EDIT. It was an isolated case, where submit event was bubbling all the way to the top, and because I named my @Output() field 'submit' - it caused double action dispatch. It is fixed now and is not relevant to the Epic issue, described above. It still persists.
EDIT 3: With the help of @jayphelps, I was able to track the issue. It turns out my actions, called from the epic chain, triggered twice. I am not sure why that happens though. Here is my old code:
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
})
This code dispatches CREATE once, CREATE_SUCCESS twice and CREATE_FAIL twice. I removed the last two @dispatch() decorators:
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
})
This code seems to work properly and only fire one of each action. I am very confused as to why this works like that. According to API docs this property decorates a single action-creator function and dispatches its return value, an action object. it is very weird, because I call CREATE and CREATE_SUCCESS identically. How does this decorator work?
EDIT 4:
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.
The solution
With the help of jayphelps. Thanks for your response. However I like the @dispatch decoration, for use inside of my components. A presonal solution I found is structuring my action chain in a manner that starter-actions (those that dispatch from inside a component) do not get dispatched via Epic. Then just decorate those starter-actions with @dispatch and it works.