loading...

Dispose redux-observable interval when Hot Module reload

terrierscript profile image terrierscript Updated on ・1 min read

In case of use interval in redux-observable's epic, this observer is not remove when reload with HMR working.

This observable is not effect store, but it is feel bad.

Solution: Use Subject to fire with module.hot.dispose and stop

FYI: If you use typescript, @types/webpack-env includes module.hot type.

import { combineEpics } from "redux-observable"
import { interval, Subject } from "rxjs"
import { map, takeUntil } from "rxjs/operators"

const disposer = new Subject() // Setup subject for dispose.

export const timerEpic = () => {
  return interval(1000).pipe(
    takeUntil(disposer), // stop when dispose subscribed.
    map((time) => ({
      type: "TIMER",
      value: time
    }))
  )
}

if (module.hot) {
  module.hot.dispose((data) => {
    disposer.next() // send dispose when fire HMR dispose event
  })
}

Split HMR part

You can split related HMR code like this.

// hotReload.ts
import { Subject } from "rxjs"
import { takeUntil } from "rxjs/operators"

const hmrDisposer = new Subject()

export const registerDisposeHandler = (module) => {
  if (module.hot) {
    module.hot.dispose(() => hmrDisposer.next())
  }
}

export const takeUntilHotReload = () => takeUntil(hmrDisposer)

Attention, you need call dispose hook on rootEpic file.

export const rootEpic = combineEpics(pingEpic)

// DO WRITE with ROOT EPIC.
registerDisposeHandler(module)

Discussion

markdown guide