#821·OpenCut

fix: carousel reInit event listener not removed on unmount (memory leak)

Author: josephdscsCreated Jun 9, 2026Updated Sep 8, 2026

Bug

In apps/web/src/components/ui/carousel.tsx (lines 97–106), the useEffect registers two Embla carousel event listeners but the cleanup function only removes one of them:

React.useEffect(() => {
  if (!api) return
  onSelect(api)
  api.on("reInit", onSelect)  // registered
  api.on("select", onSelect)  // registered

  return () => {
    // api?.off("reInit", onSelect)  ← missing
    api?.off("select", onSelect)
  }
}, [api, onSelect])

The reInit listener is never unsubscribed, causing it to accumulate in memory on each mount/unmount cycle.

Fix

return () => {
  api?.off("reInit", onSelect)
  api?.off("select", onSelect)
}

Fix is ready on a fork branch: https://github.com/josephdscs/OpenCut/tree/fix/carousel-missing-reinit-cleanup