Trying to implement an rxjs observable pipeline in React.
Codesandbox example -> https://codesandbox.io/s/optimistic-fog-xtdi4
Creating a html element (div) in React, and binding mouseover and mouseout events.
React Code to initialize this:
useEffect(() => {
const elMouseOut$ = fromEvent(elRef.current, "mouseout").subscribe(() =>
setState({ hover: "mouseout", eventType: "mouseout" })
);
const elMouseOver$ = fromEvent(elRef.current, "mouseover")
.pipe(debounceTime(2000))
.subscribe(() =>
setState({ hover: "mouseover", eventType: "mouseover" })
);
return () => {
elMouseOver$.unsubscribe();
elMouseOut$.unsubscribe();
};
}, []);
Acceptance criteria Steps.
I have tried several different combinations of operators, but cannot get things working as expected.
Note: If the mouse over debounce time is met, an ajax request is made.
Any help/advice would be appreciated, i simply do not have the rxjs chops to sort this one out.
This should do the job:
useEffect(() => {
const elMouseOver$ = fromEvent(elRef.current, "mouseover");
const elMouseOut$ = fromEvent(elRef.current, "mouseout");
const mouseoutSub = elMouseOver$.pipe(
debounceTime(2000),
tap(() => setState({ hover: 'mouseover', eventType: 'mouseover' })),
switchMap(() => elMouseOut$),
tap(() => setState({ hover: 'mouseout', eventType: 'mouseout' })),
takeUntil(scheduled(elMouseOut$, asyncScheduler)),
repeat()
);
return () => mouseoutSub.unsubscribe();
}, []);
Flow:
debounceTime - after mouseover, wait 2 secondstap - set mouseover stateswitchMap - listen for elMouseOut$tap - set mouseout statetakeUntil - end stream when mouseout occursrepeatSince switchMap and takeUntil are using the same source, I used scheduled inside the takeUntil so that the switchMap would have a chance to emit before the observable was completed.
Here's a StackBlitz that demonstrates this behavior.
I think this could be a way to solve it:
const sub = merge(
elMouseOver$.pipe(
// Step 4)
// Repeating the steps with the help of `switchMap`
switchMap(() =>
timer(2000).pipe(
// Step 2).
// Cancelling the stream and setting some state(have a look at '3)', below).
takeUntil(elMouseOut$),
// Step 1).
// This will be invoked if 2 seconds have passed after the mouseover event without
// the mouseout event taking place.
tap(() => setState({ hover: "mouseover", eventType: "mouseover" })),
)
)
),
// Step 3).
// Setting the state.
elMouseOut$.pipe(
tap(() => setState({ hover: "mouseout", eventType: "mouseout" }))
)
).subscribe();
Also, because we're subscribing to elMouseOut$ multiple times, you might want to use the share() operator so that only one event listener will be added:
const elMouseOut$ = fromEvent(elRef.current, "mouseout").pipe(
share(),
);