Reputation: 6937
I've started porting some async logic to redux-observables and I'm struggling a little with this.
My use case is this:
I have a UI overlay that's supposed to open on an OPEN_OVERLAY
action, and automatically close after three seconds (by emitting CLOSE_OVERLAY
) UNLESS either an INTERRUPT_CLOSE_OVERLAY1
or INTERRUPT_CLOSE_OVERLAY2
action is received, in which case the overlay shouldn't close.
My first take was this:
export const epic = action$ => action$.pipe(
filter(action => action.type === "OPEN_OVERLAY"),
delay(3000),
takeUntil(action$.ofType("INTERRUPT_CLOSE_OVERLAY1", "INTERRUPT_CLOSE_OVERLAY2")),
mapTo({type: "CLOSE_OVERLAY})
);
Which works, but just once. That is, if you open the overlay and interrupt it, then after closing and opening it again it will never auto-close.
I understand that this happens because takeUntil
effectively unsubscribes from the Observable. However the way I understand it with redux-observables you only define the epic once at setup and you're not supposed to be subscribing/unsubscribing.
So, how would I structure this that open/close/autoclose always works without unsubscribing?
Upvotes: 1
Views: 791
Reputation: 11969
Here would be my approach:
actions$.pipe(
filter(action => action.type === "OPEN_OVERLAY"),
switchMap(
() => timer(3000)
.pipe(
mapTo({ type: "CLOSE_OVERLAY" }),
takeUntil(action$.ofType("INTERRUPT_CLOSE_OVERLAY1", "INTERRUPT_CLOSE_OVERLAY2")),
)
)
)
It starts the timer when "OPEN_OVERLAY"
is emitted, then if the observable provided to takeUntil
does not emit in the meanwhile, it will successfully emit "CLOSE_OVERLAY"
. Otherwise, the inner observable will complete, so there is no way it can emit unless "OPEN_OVERLAY"
restarts it.
Upvotes: 2