Skip to content

perf(hooks): Add opt-in throttling to useResizeObserver and useOverflow - #7335

Closed
mattcosta7 wants to merge 9 commits into
mainfrom
perf/use-resize-observer
Closed

perf(hooks): Add opt-in throttling to useResizeObserver and useOverflow#7335
mattcosta7 wants to merge 9 commits into
mainfrom
perf/use-resize-observer

Conversation

@mattcosta7

@mattcosta7mattcosta7 commented Dec 15, 2025

Copy link
Copy Markdown
Contributor

Summary

Performance optimizations for useResizeObserver and useOverflow hooks to improve INP, with opt-in throttling for backwards compatibility.

Changes

  1. useResizeObserver - Added optional throttle parameter (4th argument, defaults to false)
    • When throttle=false (default): behaves exactly as before - no throttling, immediate callbacks
    • When throttle=true: fires callback immediately on first observation, then throttles subsequent callbacks with rAF
  2. useOverflow - Now uses useResizeObserver with throttle=true for internal optimization
  3. Backwards compatible - Existing consumers get unchanged behavior by default

API

useResizeObserver(callback,target?,depsArray?,throttle? // new - defaults to false for backwards compatibility)

Expected INP Impact (when throttle=true)

ScenarioBeforeAfterImprovement
Worst case (rapid window resizing, many observers)~50-100ms cumulative per resize<16ms (1 frame)70-85% reduction
Average case (occasional resize, few observers)~20-40ms per resize<16ms40-60% reduction
Best case (single resize event)~10-20ms<16ms~20% reduction

Why opt-in?

  • Backwards compatibility - Existing consumers get the same behavior they had before
  • Explicit intent - Consumers who want performance gains can opt-in consciously
  • Use-case flexibility - Some consumers may need every resize event (analytics, animations, cumulative calculations)

Why this matters

ResizeObserver can fire many times per frame during animations or rapid resizing:

  • Each callback may trigger state updates → re-renders
  • Without throttling, this causes jank and dropped frames
  • rAF batching ensures maximum 1 update per frame (60fps = 16ms budget)

The "first-immediate" pattern ensures initial render gets correct size without delay.


Part of the INP performance optimization effort. See #7312 for full context.

…useOverflow
- useResizeObserver fires callback immediately on first observation, then throttles with rAF
- useOverflow uses the same pattern to avoid initial flash of incorrect overflow state
- Added isFirstCallback ref pattern to skip throttling on initial mount
Part of #7312
@changeset-bot

changeset-botBot commented Dec 15, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b999a75

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@primer/reactPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actionsgithub-actionsBot added the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Dec 15, 2025
@github-actions

Copy link
Copy Markdown
Contributor

👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Or, apply the integration-tests: skipped manually label to skip these checks.

return
}
}
setHasOverflow(false)

@mattcosta7mattcosta7Dec 15, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I believe this is a current bug, since things can never go to not overflow states

@mattcosta7mattcosta7 self-assigned this Dec 15, 2025
@mattcosta7
mattcosta7 marked this pull request as ready for review December 15, 2025 20:55

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds performance optimizations to useResizeObserver and useOverflow hooks by implementing a "first-immediate" throttling pattern. The changes aim to reduce INP (Interaction to Next Paint) scores by batching ResizeObserver callbacks using requestAnimationFrame while ensuring the initial callback fires immediately to prevent UI flash.

Key changes:

  • Immediate execution on first ResizeObserver callback, then rAF throttling for subsequent callbacks
  • Proper cleanup of pending animation frames on component unmount
  • Behavioral fix in useOverflow where overflow state now correctly resets to false

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

FileDescription
packages/react/src/hooks/useResizeObserver.tsAdded first-immediate throttling pattern with rAF batching to reduce layout thrashing during rapid resize events
packages/react/src/hooks/useOverflow.tsApplied same throttling pattern and fixed logic to properly reset hasOverflow to false when overflow is removed
.changeset/perf-use-resize-observer.mdDocuments the performance improvements as a patch-level change

Comment threadpackages/react/src/hooks/useResizeObserver.ts
Comment threadpackages/react/src/hooks/useOverflow.ts
Comment threadpackages/react/src/hooks/useResizeObserver.ts
Comment threadpackages/react/src/hooks/useOverflow.ts

@francineluccafrancinelucca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM! some non-blocking comments

Comment threadpackages/react/src/hooks/useOverflow.ts
Comment threadpackages/react/src/hooks/useResizeObserver.ts
@github-actions
github-actionsBot requested a deployment to storybook-preview-7335 December 16, 2025 19:22 Abandoned
@github-actions
github-actionsBottemporarily deployed to storybook-preview-7335 December 16, 2025 19:33 Inactive
@github-actions
github-actionsBottemporarily deployed to storybook-preview-7335 December 16, 2025 19:44 Inactive
@francineluccafrancinelucca added the integration-tests: skipped manually Changes in this PR do not require an integration test label Dec 16, 2025
@siddharthkpsiddharthkp removed the integration-tests: skipped manually Changes in this PR do not require an integration test label Dec 17, 2025
@primer-integration

Copy link
Copy Markdown

👋 Hi from github/github-ui! Your integration PR is ready: https://github.com/github/github-ui/pull/9375

@primer-integration

Copy link
Copy Markdown

🔬 github-ui Integration Test Results

CheckStatusDetails
CI✅ PassedView run
Projects (Memex)✅ PassedView run
VRT✅ PassedView run

All checks passed! Your integration PR is ready for review.

@mattcosta7mattcosta7 changed the title perf(hooks): Add first-immediate throttling to useResizeObserver and useOverflowperf(hooks): Add opt-in throttling to useResizeObserver and useOverflowDec 22, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: recommendedThis change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@mattcosta7@francinelucca@siddharthkp