Skip to content

[Bug]: AuthContext storage event listener is never removed due to anonymous function identity mismatch #564

@nyxsky404

Description

@nyxsky404

Bug Description

In src/context/AuthContext.jsx, the useEffect that listens for the rh_avatar_updated localStorage event registers and attempts to remove the listener using two different anonymous arrow function instances:

// line 236 — registers reference A
window.addEventListener("storage", e => handleStorageChange(e));

// line 237 — tries to remove reference B (a brand-new function, never registered)
return () => window.removeEventListener("storage", e => handleStorageChange(e));

removeEventListener requires the exact same function object that was passed to addEventListener. Since e => handleStorageChange(e) is evaluated twice and produces two distinct closures, the cleanup is a no-op. The listener from line 236 is never actually removed.

Impact

  • In React Strict Mode (dev), effects run twice — leaving 2 dangling storage listeners on window after each mount cycle
  • The lingering listener holds a closure reference to setUserData, keeping the component fiber subtree in memory after unmount
  • On multi-tab avatar updates, setUserData can be called on an already-unmounted component

Fix

Move handleStorageChange above the addEventListener call so the same reference is used in both places:

useEffect(() => {
  const handleStorageChange = (e) => {
    if (e.key !== "rh_avatar_updated") return;
    try {
      const payload = JSON.parse(e.newValue);
      if (!payload || payload.uid !== auth?.currentUser?.uid) return;
      setUserData(prev => prev ? { ...prev, avatar: payload.avatar } : prev);
    } catch { /* ignore */ }
  };

  window.addEventListener("storage", handleStorageChange);
  return () => window.removeEventListener("storage", handleStorageChange);
}, []);

You can verify the leak in DevTools: open Application > Event Listeners > window > storage — multiple entries will be registered after the component mounts.

Metadata

Metadata

Assignees

Labels

NSoC'26NSoC 2026backendBackend/Firebase related changesbugSomething isn't workingenhancementNew feature or requestfrontendFrontend related changes (HTML/CSS/JS/React)gssocGirlScript Summer of Codegssoc26GirlScript Summer of Code 2026needs-reviewIssue needs reviewnsocNSoC

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions