Reputation: 51
I have been trying to use rxjs properly with Redux observable and Redux actions. I've tried many different combinations of calling the below functions and every possible combination has given me different errors.
Basically, I have two actions that can be dispatched in my app: SET_CIRCULAR_DATA
and SET_MODAL_OVER_DEEP_LINK_FLAG
.
I'd like another action to be dispatched, determineFoundInProducts()
when SET_MODAL_OVER_DEEP_LINK_FLAG
happens followed by the first (successful) SET_CIRCULAR_DATA
action. Any subsequent SET_CIRCULAR_DATA
actions should be ignored until SET_MODAL_OVER_DEEP_LINK_FLAG
happens again. Because of this need, I felt withLatestFrom()
made the most sense. I also thought that takeUntil()
and repeat()
might be helpful to help me accomplish what I need, though I'm not including them in this code example because I'm stuck at the withLatestFrom()
part.
I've tried different combinations of piping, not piping, using switchMap, map, mapTo, but nothing seems to work. I am importing all the used rxjs functions and I'm combining epics at the root, so it couldn't be that. I just can't seem to get the right combination to not get this to error.
Some examples of errors are
I am using RXJS ^5.5.6 and Redux Observable ^0.17.0.
import 'rxjs';
import { Observable } from 'rxjs/Observable';
import { withLatestFrom, map, tap, mergeMap } from 'rxjs/operators';
import ....all the types and actions
export const handleProductDetailsModalOnLoginRedirect = (action) =>
action.ofType(weeklyAdTypes.types.SET_CIRCULAR_DATA).pipe(
withLatestFrom(
action.ofType(navigationTypes.types.SET_MODAL_OVER_DEEP_LINK_FLAG)
),
mergeMap(([first, second]) => {
console.log(first, second);
return determineFoundInProducts();
})
);
I was struggling in my original post to determine what part of the code was breaking. What I had trouble with was that the redux observable action could not communicate with the rxjs functions. What I found was that piping appropriately piped (pun intended) the action to be workable with rxjs functions. Here is what I did.
action.ofType(navigationTypes.types.INIT_REDIRECT_MODAL_LOGIC)
.switchMap(() =>
action.ofType(weeklyAdTypes.types.SET_CIRCULAR_DATA)
.withLatestFrom(action.ofType(navigationTypes.types.SET_MODAL_OVER_DEEP_LINK_FLAG))
.take(1)
.pipe(
map(([first]) => {
// Do stuff
return determineFoundInProducts();
}))
)
Upvotes: 0
Views: 959
Reputation: 51
The above answer will definitely help others. However, what I was struggling with was having redux observable action communicate with RXJS functions. Please see my edit to my original post for solution.
Upvotes: 0
Reputation: 15401
The answer depends on what you want to happen if multiple SET_MODAL_OVER_DEEP_LINK_FLAG
actions are dispatched before any SET_CIRCULAR_DATA
action is, as well as whether they should some how be paired together with some sort of unique ID or not.
It sounds most likely like you're looking for exhaustMap
.
The exhaustMap
operator is basically the opposite behavior of switchMap
. It maps inputs to inner observable and flattens its output, ignore other input values until that observable completes. It exhausts the inner Observable.
In your use case it means that we first listen for SET_MODAL_OVER_DEEP_LINK_FLAG
, then we listen for a single SET_CIRCULAR_DATA
, but while we're waiting for that subsequent SET_CIRCULAR_DATA
we ignore all possibly incoming SET_MODAL_OVER_DEEP_LINK_FLAG
actions. Note that the take(1)
is important, because otherwise we'll listen for a stream of every SET_CIRCULAR_DATA
, not just one.
export const handleProductDetailsModalOnLoginRedirect = (action) =>
action.ofType(navigationTypes.types.SET_MODAL_OVER_DEEP_LINK_FLAG)
.exhaustMap(() =>
action.ofType(weeklyAdTypes.types.SET_CIRCULAR_DATA)
.take(1)
.map(() => determineFoundInProducts())
);
Btw it's common to ask Redux Observable questions that are actually just RxJS questions. This is a cool thing to note because the RxJS community is massive so you'll find a TON more resources on it, as well as have a better chance of getting help if you're able to rephrase questions to be agnostic of Redux Observable--e.g. change ofType('TYPE')
to a filter(d => d.type === 'TYPE')
Upvotes: 2