reactjstypescriptreact-hooksrxjs

Creating OnIdle in rxjs


While learning the rxJS, I have the following piece of code which is for checking whenever there is an activity on browser window like mouse moved, clicked or keyboard used. think of it as reverse of onIdle

import { fromEvent, throttle, debounce, interval, merge } from 'rxjs';
import { map } from 'rxjs/operators';

function useActivated(fn: (event: string) => void) {
  useEffect(()=>{
    const clicks = fromEvent(document, 'click')
    const move = fromEvent(window, 'mousemove')
    const keys = fromEvent(window, 'keypress')

    const merged = merge(
      keys.pipe(map((x) => 'key')),
      clicks.pipe(map((x) => 'mouse click')),
      move.pipe(map((x) => 'mouse move'))
    )

    const final = merged.pipe(throttle(() => interval(1000)))
    const subscription = final.subscribe((x) => fn(x));

    return () => subscription.unsubscribe()
  }, [])
}

useActivated((x) => console.log(x));

I want to be able to create a function useOnIdle() whose output is excelt reverse of this. the logic is,

  1. we would monitor keyboard, mouse and interval events
  2. if no event of mouse or keyboard occurs but the interval fires, then the browser is idle and we Fire onIdle
  3. if any mouse or keyboard event occurs before interval event, the browser is not idle and we will NOT fire any event

how can I implement this logic, or reverse the working of my current code.


Solution

  • You may try with the bufferTime operator instead of throttle and filter, something like this

    function useIdle(fn: (event: string) => void) {
      useEffect(()=>{
        const clicks = fromEvent(document, 'click')
        const move = fromEvent(window, 'mousemove')
        const keys = fromEvent(window, 'keypress')
    
        const merged = merge(
          keys.pipe(map((x) => 'key')),
          clicks.pipe(map((x) => 'mouse click')),
          move.pipe(map((x) => 'mouse move'))
        )
    
        const final = merged.pipe(
          // buffer the notifications of merged observable over an interval
          bufferTime(1000),
          // if the buffer is empty, then the system has been idle
          filter(vals => vals.length === 0),
          map(() => 'idle')
        )
        const subscription = final.subscribe((x) => fn(x));
    
        return () => subscription.unsubscribe()
    
      }, [])
    }