Skip to content

fix: kill GSAP timeline instances in useEffect cleanup to prevent mem…#308

Open
HamidKhan1001 wants to merge 1 commit intoAOSSIE-Org:mainfrom
HamidKhan1001:fix/gsap-timeline-memory-leak
Open

fix: kill GSAP timeline instances in useEffect cleanup to prevent mem…#308
HamidKhan1001 wants to merge 1 commit intoAOSSIE-Org:mainfrom
HamidKhan1001:fix/gsap-timeline-memory-leak

Conversation

@HamidKhan1001
Copy link

@HamidKhan1001 HamidKhan1001 commented Feb 21, 2026

fix: kill GSAP timeline instances in useEffect cleanup to prevent memory leak

Problem

Four GSAP timelines in app/page.jsx were never killed in the
useEffect cleanup function, causing memory to accumulate on every
remount/scroll.

Affected timelines:

  • heroTl (line 45)
  • techStackTl (line 109)
  • aboutTl (line 142)
  • downloadTl (line 181)

Evidence

Heap snapshots taken before and after scrolling show the leak clearly:

  • Before scrolling: 6.7 MB heap
  • After scrolling: 31.5 MB heap (+370% growth)
  • Timeline ×11 and Tween ×62 visible as retained objects
image image

Fix

Added .kill() calls for all four timelines in the cleanup return block.

Related

Closes #[your issue number]
Relates to #292

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking CHANGE which fixes an issue)
    )

How Has This Been Tested?

Live version and my local version

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced resource cleanup to prevent potential memory leaks and orphaned animations during page navigation.

@HamidKhan1001 HamidKhan1001 requested a review from a team as a code owner February 21, 2026 18:44
@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

The component's cleanup function now explicitly calls .kill() on four GSAP timelines (heroTl, techStackTl, aboutTl, downloadTl) to ensure proper termination when the component unmounts, preventing orphaned animations and potential memory leaks.

Changes

Cohort / File(s) Summary
GSAP Timeline Cleanup
app/page.jsx
Added explicit .kill() calls for four GSAP timelines (heroTl, techStackTl, aboutTl, downloadTl) in the effect cleanup function to ensure proper animation lifecycle management on component unmount.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 Four timelines now rest with care,
When components unmount into thin air,
No orphaned animations left behind,
Just clean-up code, perfectly aligned! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: killing GSAP timeline instances in useEffect cleanup to prevent memory leaks, which matches the actual changes in the pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/page.jsx (1)

84-106: ⚠️ Potential issue | 🟠 Major

Feature-item timelines are not killed in cleanup — the memory leak this PR aims to fix persists for these.

Each loop iteration (lines 84–106) creates a tl timeline that is registered in GSAP's global ticker. The ScrollTrigger.getAll().forEach((t) => t.kill()) on line 223 kills the ScrollTrigger controllers but leaves the timeline objects themselves alive in GSAP's internal registry — exactly the same class of leak being fixed for the named timelines. Because tl is block-scoped inside the forEach callback, there is no reference available at cleanup time.

The most idiomatic fix for this class of problem in React is gsap.context(), which automatically tracks every GSAP object created inside it (including loop-local timelines) and cleans all of them up on ctx.revert():

♻️ Proposed fix using gsap.context() — replaces the entire effect body
  useEffect(() => {
+   const ctx = gsap.context(() => {
      // Initialize Lenis for smooth scrolling
      const lenis = new Lenis({ ... });

      let rafId;
      let isActive = true;

      function raf(time) {
        if (!isActive) return;
        lenis.raf(time);
        rafId = requestAnimationFrame(raf);
      }
      rafId = requestAnimationFrame(raf);

      // ... all heroTl, feature forEach tl, techStackTl, aboutTl, downloadTl ...

      return () => {
        isActive = false;
        if (rafId != null) cancelAnimationFrame(rafId);
        lenis.destroy();
-       heroTl.kill();
-       techStackTl.kill();
-       aboutTl.kill();
-       downloadTl.kill();
        ScrollTrigger.getAll().forEach((t) => t.kill());
      };
+   });
+
+   return () => ctx.revert();   // kills every GSAP object created inside the context
  }, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/page.jsx` around lines 84 - 106, The feature-item loop creates
block-scoped timelines (tl) via gsap.utils.toArray(".feature-item") that are not
tracked and thus not killed on cleanup; wrap the entire GSAP setup (the
gsap.utils.toArray(...) forEach and tl creation) inside a gsap.context(() => {
... }) so all timelines and ScrollTriggers are automatically tracked, store the
context in a variable (e.g., ctx) in the effect, and call ctx.revert() in the
effect cleanup to ensure tl and related GSAP objects are disposed; keep the
existing ScrollTrigger config but remove the need to manually kill timelines
since ctx.revert() handles them.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@app/page.jsx`:
- Around line 84-106: The feature-item loop creates block-scoped timelines (tl)
via gsap.utils.toArray(".feature-item") that are not tracked and thus not killed
on cleanup; wrap the entire GSAP setup (the gsap.utils.toArray(...) forEach and
tl creation) inside a gsap.context(() => { ... }) so all timelines and
ScrollTriggers are automatically tracked, store the context in a variable (e.g.,
ctx) in the effect, and call ctx.revert() in the effect cleanup to ensure tl and
related GSAP objects are disposed; keep the existing ScrollTrigger config but
remove the need to manually kill timelines since ctx.revert() handles them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: GSAP timeline instances not cleaned up in useEffect memory leak in page.jsx

1 participant