Reputation: 443
I am using Redux-Observable Epic in a React & Redux project. I have multiple actions need to emit, originally this is what I have been doing,
1) Catch the START_ACTION in the Epic
2) Fetch remote data
3) Return a new Observanble
for example:
import fetch from 'isomorphic-fetch';
import {Observable} from 'rxjs/Observable';
import {switchMap} from 'rxjs/operator/switchMap';
import {mergeMap} from 'rxjs/operator/mergeMap';
const fetchAsync = (arg) => {
// return an observable of promise
return Observable::from(fetch(url + arg));
}
export function myEpic = (action$) => {
action$.ofType(START_ACTION)
::switchMap(action => {
return fetchAsync('/action.payload')
::mergeMap(result => {
return Observable::of({type: ACTION_COMPLETE, payload: result})
})
})
};
Now what if I have another action SECOND_ACTION
need to be emitted after the START_ACTION
and before the ACTION_COMPLETE
? In other word, without making sure the SECOND_ACTION
hits the reducer, the ACTION_COMPLETE
should not be emitted.
I could write another separate Epic function to do this, but is there any other easier way?
Upvotes: 0
Views: 1118
Reputation: 15401
To simplify the question, I just want to emit the SECOND_ACTION before the async.
To emit another action before performing the fetchAsync
, you can either use Observable.concat
or the startWith
operator, which is basically sugar for the concat.
export function myEpic = (action$) => {
action$.ofType(START_ACTION)
::switchMap(action => {
return fetchAsync('/action.payload')
::map(result => ({ type: ACTION_COMPLETE, payload: result })
::startWith({ type: SECOND_ACTION })
})
};
Since SECOND_ACTION
synchronously follows START_ACTION
, keep in mind that often you should just have your reducers listen for START_ACTION
instead of emitting another action. Multiple reducers transitions state from the same action is normal and one of the primary benefits of redux.
That said, there are certainly some times where the separation of concerns is more ideal, so this is more of a general tip.
If you want to emit two actions sequentially you can pass the additional actions as arguments to Observable.of(...actions)
since it accepts any number of arguments and emits them sequentially.
export function myEpic = (action$) => {
action$.ofType(START_ACTION)
::switchMap(action => {
return fetchAsync('/action.payload')
::mergeMap(result => {
return Observable::of(
{ type: SECOND_ACTION },
{ type: ACTION_COMPLETE, payload: result }
)
})
})
};
If this isn't what you meant, I apologize. The question isn't clear.
Upvotes: 1