Skip to content

Add cleanup to timers and listeners registered in effects (batch sweep) #31509

Description

@MajorLift

Performance audit finding · Severity: Medium (batch) · Effort: Medium · Fix risk: Simple · Test safety net: Partial
Owner: per-file CODEOWNERS
Scope: timers and listeners registered in effects without cleanup, app-wide — GitHub code search sizes the triage surface at 39 files co-locating setInterval with useEffect and 34 files co-locating addEventListener with useEffect under app/ (file-level co-occurrence; each hit needs a teardown check, many will be fine)

What is this about?

Every setInterval, setTimeout, and addEventListener inside a useEffect must be torn down in the effect's cleanup function. A leaked interval keeps firing (and dispatching) after unmount; a leaked listener pins its closure — and everything the closure captured — out of garbage collection. Mount/unmount cycles stack additional copies. The extension's equivalent sweep (MetaMask-planning#6541) found 122 instances; mobile's known anchors:

Detection recipe (from the skill's mm-useeffect-antipatterns / audit playbook):

grep -rn "setInterval\|setTimeout\|addEventListener\|\.on(" app --include="*.ts" --include="*.tsx" | grep -v ".test." | grep -vE "clear|remove|off\("

For each hit, confirm a matching teardown (return () => … with clearInterval/clearTimeout/removeEventListener/.off()); fix or waive with a stated reason (app-lifetime singletons).

Scenario

N/A — see Technical Details.

Design

N/A — internal performance change; no UI/design impact.

Technical Details

Fix per site: return the teardown from the effect. Once patterns repeat, prefer the shared-hook route already prescribed in #31495 (useEventListener with automatic cleanup, per the extension's MetaMask-planning#7166) so cleanup is the default rather than per-site diligence.

Threat Modeling Framework

N/A — performance-only change; behavior is preserved, no new data flow / trust boundary / attack surface.

Acceptance Criteria

  • All sweep hits triaged: teardown added or waived with reason.
  • Navigate-in/navigate-out N times on touched screens: timer/listener counts stay flat (heap snapshot or js-memory-leaks recipe); no post-unmount dispatches.

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    To be fixed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions