DEV Community

bglgwyng
bglgwyng

Posted on

Better `useEffect` is here

react-eff-hook introduces useEff, an enhanced useEffect powered by Generator.

Usage

useEff(function*() {
  while (true) {
    yield delay(1000)

    setCount((x) => x + 1)
  }
}, [])
Enter fullscreen mode Exit fullscreen mode

So, why is it better? Let's compare it to the code using useEffect.

useEffect(() => {
  let cancelled = false
  void (async () => {
    while (!cancelled) {
      await delay(1000)

      setCount((x) => x + 1)
    }
  })()
  return () => { cancelled = true }
}, [])
Enter fullscreen mode Exit fullscreen mode
  • Ugly IIFE to avoid being asynchronous callback
  • Manually stop the loop on cleanup

They are all gone with useEff.

If you wish to have the promise value's type inferred, use wait in conjunction with yield* like so:

const data = yield* wait(fetch(url))
Enter fullscreen mode Exit fullscreen mode

Then you will get data with its right type.

Furthremore, useEffect doesn't work fine with new using syntax in TypeScript 5.2.

useEff does.

class Interval {
  constructor(fn: () => void, interval: number) {
    this.interval = setInterval(fn, interval); 
  }

  [Symbol.dispose]() {
    clearInterval(this.interval)
  }
}

const never = new Promise(() => {})

useEff(function*() {
  using interval = new Interval(
    () => { setCount((x) => x + 1) }, 
    1000)

  yield never
}, [])
Enter fullscreen mode Exit fullscreen mode

Also, you can use useLayoutEff and useInsertionEff which are better versions of useLayoutEffect and useInsertionEffect respectively.

Caveat(or Feature?)

While useEff automatically handles cleanup, it handles erros in a different way from useEffect.

Both useEff and useEffect trigger cleanup functions upon deps changes or component unmounts, ensuring you don't need to worry about successful effects.

useEffect disregards errors thrown by promises within it, whereas the disposables within useEff invoke their dispose functions when any error occurs.

While this may be seen as a more desirable behavior, it may not be compatible with useEffect.

However, I'm not entirely certain. Please let me know if you encounter any issues with this behavior.

Top comments (0)