Skip to content

⚡ Bolt: Optimize BackToTop scroll event listener#109

Open
anyulled wants to merge 2 commits intomainfrom
bolt/optimize-backtotop-scroll-4421907313861527540
Open

⚡ Bolt: Optimize BackToTop scroll event listener#109
anyulled wants to merge 2 commits intomainfrom
bolt/optimize-backtotop-scroll-4421907313861527540

Conversation

@anyulled
Copy link
Owner

@anyulled anyulled commented Mar 20, 2026

💡 What: Wrapped the onScroll callback in components/elements/BackToTop.tsx with a throttle using requestAnimationFrame and added { passive: true } to the scroll event listener.

🎯 Why: The previous implementation triggered a React state update (setHasScrolled) on every single scroll event tick synchronously, which can block the main thread and cause scrolling jank.

📊 Impact: Significantly reduces CPU usage and eliminates potential jank during fast scrolling by batching state updates to the browser's render cycle and allowing the browser to optimize scrolling.

🔬 Measurement:

  • Start the dev server.
  • Profile the application in Chrome DevTools using the Performance tab.
  • Scroll up and down rapidly.
  • Observe the reduced number of onScroll function calls and React render cycles in the Main thread flame chart compared to the unoptimized version.

PR created automatically by Jules for task 4421907313861527540 started by @anyulled

Summary by CodeRabbit

  • Performance Improvements
    • Optimized scroll event handling for the back-to-top button to improve page responsiveness and reduce performance impact during scrolling.
    • Results in smoother scrolling and more responsive appearance/disappearance of the back-to-top control on long pages.

Throttled the scroll event listener in `BackToTop` using `requestAnimationFrame` to prevent main-thread blocking and excessive React re-renders. Also added `{ passive: true }` to the event listener to allow the browser to scroll smoothly.

Expected impact: Significant reduction in CPU usage and jank during fast scrolling.

Co-authored-by: anyulled <100741+anyulled@users.noreply.github.com>
@vercel
Copy link

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devbcn Ready Ready Preview, Comment Mar 20, 2026 9:46am

@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@qodo-code-review
Copy link

Review Summary by Qodo

Optimize BackToTop scroll event listener with throttling

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Throttles scroll events using requestAnimationFrame to prevent main-thread blocking
• Adds passive event listener flag for smoother browser scrolling
• Reduces excessive React re-renders during fast scrolling
• Cancels pending animation frames on component unmount
Diagram
flowchart LR
  A["Scroll Event"] -->|"requestAnimationFrame throttle"| B["State Update Batched"]
  C["Passive Listener"] -->|"allows browser optimization"| D["Smooth Scrolling"]
  B --> E["Reduced CPU Usage"]
  D --> E
  F["Cleanup"] -->|"cancelAnimationFrame"| G["Memory Leak Prevention"]
Loading

Grey Divider

File Changes

1. components/elements/BackToTop.tsx ✨ Enhancement +20/-3

Throttle scroll events and add passive listener

• Wrapped onScroll callback with requestAnimationFrame throttling to batch state updates
• Added { passive: true } option to scroll event listener for browser optimization
• Implemented state object to track throttling state and animation frame ID
• Added cancelAnimationFrame cleanup in useEffect return to prevent memory leaks

components/elements/BackToTop.tsx


Grey Divider

Qodo Logo

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the performance and user experience of the "Back to Top" component by optimizing its scroll event handling. The changes aim to reduce CPU usage and eliminate potential UI jank during rapid scrolling, ensuring a smoother interaction for users.

Highlights

  • Scroll Event Throttling: Implemented scroll event throttling for the onScroll callback in components/elements/BackToTop.tsx using requestAnimationFrame. This batches state updates to the browser's render cycle, preventing excessive re-renders and main-thread blocking.
  • Passive Event Listener: Added { passive: true } to the scroll event listener. This allows the browser to perform smooth scrolling without waiting for JavaScript execution, further optimizing performance.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 20, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Remediation recommended

1. Redundant optimization block comment 📘 Rule violation ⚙ Maintainability
Description
The newly added block comment largely restates what the code already makes obvious (using
requestAnimationFrame throttling and a passive scroll listener) instead of focusing on non-obvious
rationale. This violates the requirement to avoid behavior-narrating inline comments.
Code

components/elements/BackToTop.tsx[R8-13]

+    /*
+     * ⚡ Bolt Optimization:
+     * - Throttles scroll events using requestAnimationFrame to prevent main-thread blocking and excessive re-renders.
+     * - Uses passive event listener to allow the browser to perform smooth scrolling without waiting for JS execution.
+     * Expected impact: Significant reduction in CPU usage and jank during fast scrolling.
+     */
Evidence
PR Compliance ID 95942 disallows new inline comments that restate behavior. The added comment
explains that it throttles scroll events with requestAnimationFrame and uses a passive
listener—details already directly evident from the immediately following code.

Rule 95942: Restrict inline comments to explaining non-obvious rationale, not restating behavior
components/elements/BackToTop.tsx[8-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new inline block comment was added that mostly narrates behavior already clear from the code (mentions `requestAnimationFrame` throttling and passive scroll listeners) rather than focusing on non-obvious rationale.

## Issue Context
Compliance requires inline comments to explain *why* (constraints/trade-offs) rather than restating *what* the code does.

## Fix Focus Areas
- components/elements/BackToTop.tsx[8-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d6de825-f37f-4b41-aa0c-7a5105063fd4

📥 Commits

Reviewing files that changed from the base of the PR and between c9a0c17 and f142adb.

📒 Files selected for processing (1)
  • .commitlintrc.yml
✅ Files skipped from review due to trivial changes (1)
  • .commitlintrc.yml

📝 Walkthrough

Walkthrough

Scroll handling in BackToTop was changed from immediate state updates on every scroll event to a throttled requestAnimationFrame approach with an isTicking guard and cancelAnimationFrame cleanup; the scroll listener is now registered as passive. Commitlint config quoting was adjusted.

Changes

Cohort / File(s) Summary
Scroll handler / BackToTop
components/elements/BackToTop.tsx
Replaced direct setHasScrolled(window.scrollY > 100) on every scroll with a throttled requestAnimationFrame update guarded by isTicking. Listener added as { passive: true }. Cleanup now cancels scheduled animation frames via window.cancelAnimationFrame(state.tickingId).
Commitlint config
.commitlintrc.yml
Adjusted extends value to use double-quoted string: "@commitlint/config-conventional" (quoting only).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I watched the page while nibbling thyme,
I hop, I tick, I time the rhyme.
Now scrolls are gentle, smooth, and bright—
I dance in frames from night to light. 🥕✨

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main optimization work: throttling the scroll event listener in BackToTop using requestAnimationFrame to reduce jank and CPU usage.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bolt/optimize-backtotop-scroll-4421907313861527540
📝 Coding Plan
  • Generate coding plan for human review comments

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
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively optimizes the scroll event listener in the BackToTop component by using requestAnimationFrame to throttle state updates and adding { passive: true } to the event listener. This is a great performance improvement that will prevent scrolling jank. I've added one suggestion to further enhance the code's readability and maintainability by extracting a magic number and using more descriptive variable names.

Comment on lines +14 to +30
const state = { isTicking: false, tickingId: 0 };

const onScroll = () => {
setHasScrolled(window.scrollY > 100);
if (!state.isTicking) {
state.tickingId = window.requestAnimationFrame(() => {
setHasScrolled(window.scrollY > 100);
state.isTicking = false;
});
state.isTicking = true;
}
};

window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
window.addEventListener("scroll", onScroll, { passive: true });
return () => {
window.removeEventListener("scroll", onScroll);
window.cancelAnimationFrame(state.tickingId);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For improved readability and maintainability, I suggest a few refinements:

  • Extract Magic Number: The scroll threshold 100 is a magic number. Extracting it into a named constant like SCROLL_THRESHOLD_PX makes its purpose clear and simplifies future modifications.
  • Descriptive Naming: Renaming state to throttleState and tickingId to animationFrameId more accurately describes their roles within the throttling logic.

These changes make the implementation easier to understand at a glance.

    const SCROLL_THRESHOLD_PX = 100;
    const throttleState = { isTicking: false, animationFrameId: 0 };

    const onScroll = () => {
      if (!throttleState.isTicking) {
        throttleState.animationFrameId = window.requestAnimationFrame(() => {
          setHasScrolled(window.scrollY > SCROLL_THRESHOLD_PX);
          throttleState.isTicking = false;
        });
        throttleState.isTicking = true;
      }
    };

    window.addEventListener("scroll", onScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.cancelAnimationFrame(throttleState.animationFrameId);
    };

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.

🧹 Nitpick comments (1)
components/elements/BackToTop.tsx (1)

8-13: Tighten the optimization comment to focus on rationale only.

The block currently mixes “what it does” with “why.” Prefer a shorter why-focused note to match the repo’s self-documenting rule.

Proposed edit
-    /*
-     * ⚡ Bolt Optimization:
-     * - Throttles scroll events using requestAnimationFrame to prevent main-thread blocking and excessive re-renders.
-     * - Uses passive event listener to allow the browser to perform smooth scrolling without waiting for JS execution.
-     * Expected impact: Significant reduction in CPU usage and jank during fast scrolling.
-     */
+    /*
+     * Use rAF + passive scroll listener to reduce scroll-thread contention and avoid
+     * unnecessary work during rapid scrolling.
+     */

As per coding guidelines, "Code must be self-documenting. Only explain why non-obvious decisions were made in comments. DO NOT add inline comments explaining what code does."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/elements/BackToTop.tsx` around lines 8 - 13, Update the comment
block in BackToTop.tsx (near the BackToTop component/scroll handler) to remove
the "what it does" lines and keep a single-line rationale explaining why the
optimization exists (e.g., to reduce CPU usage and jank during fast scrolling);
replace the multi-bullet description about throttling and passive listeners with
a concise why-focused note that the requestAnimationFrame/passive listener
approach reduces main-thread work and improves scroll smoothness.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@components/elements/BackToTop.tsx`:
- Around line 8-13: Update the comment block in BackToTop.tsx (near the
BackToTop component/scroll handler) to remove the "what it does" lines and keep
a single-line rationale explaining why the optimization exists (e.g., to reduce
CPU usage and jank during fast scrolling); replace the multi-bullet description
about throttling and passive listeners with a concise why-focused note that the
requestAnimationFrame/passive listener approach reduces main-thread work and
improves scroll smoothness.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3fa11dec-0dbe-467e-8459-df780a7cc832

📥 Commits

Reviewing files that changed from the base of the PR and between b1e2ed4 and c9a0c17.

📒 Files selected for processing (1)
  • components/elements/BackToTop.tsx

Ran `npm run format` to automatically apply prettier formatting across the codebase to fix CI format check failures.

Co-authored-by: anyulled <100741+anyulled@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant