Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

198
Visualizações
RXJS observables cancel mouseover stream after mouseout event

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.

  1. When I mouse over, after a delay of 2 seconds i need to make a state update.
  2. If I mouse out at any time BEFORE the 2 second delay I need to cancel the mouseover stream, and set some state. (THIS STEP IS BROKEN)
  3. If I mouse out any time AFTER the 2 second delay, I need to set some state.
  4. This should be repeatable, in the sense that if i mouse over, mouse out and mouse over again we start from Step 1.

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.

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

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 seconds
  • tap - set mouseover state
  • switchMap - listen for elMouseOut$
  • tap - set mouseout state
  • takeUntil - end stream when mouseout occurs
  • repeat

Since 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.

about 4 years ago · Juan Pablo Isaza Relatório

0

CodeSandbox solution.


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(),
);
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda