Jaishree2310/GlassyUI-Components

Bug: auto-dismissed toasts accumulate in state because removeItem is never called on timer expiry

オープン

#674 opened on 2026/06/02

 (5 件のコメント) (0 件のリアクション) (1 人の担当者)TypeScript (217 件のフォーク)auto 404
good first issuegssoc'26gssoc:approvedlevel:beginnertype:bug

Repository metrics

Stars
 (114 個のスター)
PR merge metrics
 (PR metrics pending)

説明

Description

The Toast component has a split code path for dismissal that causes auto-dismissed toasts to remain in the parent toasts state array indefinitely.

When the dismiss button is clicked, the handler correctly runs the hide animation and then calls removeItem(id) after 400 ms. When autoDismiss fires, however, the useEffect timer only sets hide = true (which adds the hide-toast CSS class and runs the animation) but never calls removeItem(id) afterward. The toast entry stays in the array forever.

Over a session where a user generates many toasts and lets them auto-expire, the toasts array grows without bound. Every lingering entry holds a closure over the toaster setter, and React keeps the component subtree mounted (hidden by CSS, not unmounted), resulting in accumulated state and stale component instances.

Affected file: src/components/Toast.tsx

// lines 29-34 in Toast.tsx
useEffect(() => {
  const timer = setTimeout(() => {
    setHide(true);       // sets CSS class, but removeItem is never called
  }, autoDismiss);
  return () => clearTimeout(timer);
}, []);                  // autoDismiss and id are also missing from deps

Compare with the button handler which correctly removes the entry:

onClick={e => {
  e.currentTarget.parentElement?.classList.add('hide-toast');
  setTimeout(() => {
    removeItem(id);      // correctly removes from toasts array
  }, 400);
}}

Steps to Reproduce

  1. Open the Toast demo page in the application.
  2. Click "Show Toast" repeatedly to generate 5 or more toasts.
  3. Wait for all toasts to auto-dismiss (default is 8000 ms).
  4. Open React DevTools and inspect the toasts state on the parent ToastPage component.

Expected: array length is 0 after all toasts auto-expire. Actual: array retains all auto-dismissed toast entries; length equals the total number of toasts ever generated.

Environment Information

  • Browser: Chrome 124 / Firefox 125
  • OS: macOS 14 / Windows 11
  • Node: 20.x
  • Framework: React 18 with TypeScript

Expected Behavior

After the autoDismiss timer fires and the hide animation completes, the toast is removed from the parent toasts state array, identical to the behavior of the manual dismiss button. The array length should decrease by one for each auto-dismissed toast.

Actual Behavior

The autoDismiss timer sets hide = true, which applies the hide-toast CSS animation and visually removes the toast. The toast object remains in the toasts array. Each auto-dismissed toast adds a persistent entry that is never cleaned up.

Screenshots or Recordings

Not included - the bug is observable directly in React DevTools by watching the toasts state array while toasts auto-expire.

Additional Context

Root cause: The useEffect in Toast.tsx (lines 29-34) only mirrors the visual side of dismissal (CSS class) without calling removeItem(id) to synchronize state. The manual dismiss button does both steps, but the timer path skips the state cleanup.

Secondary issue: autoDismiss and id are both used inside the effect but are absent from the dependency array. If autoDismiss changes after mount the old timer fires with the original value.

Proposed fix:

useEffect(() => {
  const timer = setTimeout(() => {
    setHide(true);
    setTimeout(() => removeItem(id), 600); // match animation duration
  }, autoDismiss);
  return () => clearTimeout(timer);
}, [autoDismiss, id]);

Severity: Medium - silent state growth causes increased memory usage in long-running sessions; no immediate crash but degraded performance over time.

Expected GSSoC points: Level 2 (intermediate bug fix touching component lifecycle and state management)

Suggested Labels

bug, level:intermediate, gssoc'26

Checklist

  • Searched existing issues, not a duplicate
  • Read CONTRIBUTING.md guidelines
  • Read README and understand project scope
  • Provided clear reproduction steps
  • Provided environment information
  • Described expected vs. actual clearly
  • No AI/Claude mentions
  • No em dashes or double hyphens
  • Repository verified as GSSoC

コントリビューターガイド