Our dashboard got slower the longer someone left it open. We assumed it was their laptop. It was every event listener we never cleaned up.

Every listener, subscription, or interval needs a matching teardown tied to the same lifecycle event that created it.

frontendperformance

Problem

Users started complaining the dashboard felt sluggish “after a while.” We assumed it was their machines, until someone left a tab open overnight and came back to a page that took 12 seconds to respond to a click.

Why it happens

Every time a widget re-rendered, it attached a new scroll and resize listener to the window, and never removed the old ones. Each refresh, each filter change, each auto-updating chart added a few more listeners that never got cleaned up. None of it was a “memory leak” in the traditional sense; it was accumulation nobody was watching for.

Better approach

Every listener, subscription, or interval you attach needs a matching teardown, tied to the same lifecycle event that created it. Treat “what removes this?” as a required question at the moment you write the line that adds it, not something to debug later.

Example

We audited every addEventListener call in the codebase and paired each one with a cleanup function on unmount. The same dashboard, left open for eight hours, now performs identically to a fresh load.