Skip to content

Fix usePaneWidth triggering unnecessary React re-renders on every window resize#7824

Open
jonrohan wants to merge 2 commits intomainfrom
fix_pagelayout_unnecessary_rerenders
Open

Fix usePaneWidth triggering unnecessary React re-renders on every window resize#7824
jonrohan wants to merge 2 commits intomainfrom
fix_pagelayout_unnecessary_rerenders

Conversation

@jonrohan
Copy link
Copy Markdown
Member

@jonrohan jonrohan commented May 8, 2026

Closes #7801

Overview

When SplitPageLayout has a resizable pane (resizable={true}), the usePaneWidth hook calls startTransition(() => setMaxPaneWidth(actualMax)) inside syncAll() on every window resize event — even when actualMax hasn't changed. Unlike normal setState, startTransition does not bail out on same-value updates, so this triggers unnecessary React concurrent renders on every resize tick (~60/sec during a drag).

On pages with many components consuming the layout context (e.g. GitHub PR conversation tab), this produces ~11 React scheduler calls totaling ~108ms in a single animation frame with CPU throttle, causing visible jank.

Fix: Added a maxPaneWidthRef to track the previous maxPaneWidth value, and guarded the startTransition call so it only fires when actualMax has actually changed or when the current width needs to be clamped. The CSS variable updates, ref updates, and ARIA updates (which don't cause React re-renders) remain unconditional.

Changelog

New

  • Added a Storybook performance test story (Re-render Counter (Issue #7801)) to help verify resize re-render behavior with React DevTools Profiler.

Changed

  • usePaneWidth: syncAll() now skips startTransition when the computed max pane width hasn't changed, avoiding unnecessary React re-renders on window resize.

Removed

None

Rollout strategy

  • Patch release

Testing & Reviewing

  1. Open the new Storybook story: Components/PageLayout/Performance Tests/Re-render Counter (Issue usePaneWidth triggers unnecessary React re-renders on every window resize #7801)
  2. Open React DevTools Profiler, enable "Highlight updates when components render"
  3. Resize the browser window within the same side of the 1280px breakpoint
  4. Verify no unnecessary re-renders occur (components should not flash/highlight)
  5. Resize across the 1280px breakpoint and verify the state does update correctly

Unit test added: should skip startTransition when maxPaneWidth has not changed (#7801) in usePaneWidth.test.ts

Merge checklist

  • Added/updated tests
  • Added/updated documentation
  • Added/updated previews (Storybook)
  • Changes are SSR compatible
  • Tested in Chrome
  • Tested in Firefox
  • Tested in Safari
  • Tested in Edge
  • (GitHub staff only) Integration tests pass at github/github-ui

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 8, 2026

🦋 Changeset detected

Latest commit: b43e27c

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

This PR includes changesets to release 1 package
Name Type
@primer/react Patch

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-actions github-actions Bot added staff Author is a staff member integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm labels May 8, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

⚠️ Action required

👋 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. Check the integration testing docs for step-by-step instructions. Or, apply the integration-tests: skipped manually label to skip these checks.

To publish a canary release for integration testing, apply the Canary Release label to this PR.

Fix `usePaneWidth` triggering unnecessary React re-renders on every window resize
@jonrohan jonrohan requested a review from talum May 8, 2026 18:06
@jonrohan jonrohan marked this pull request as ready for review May 8, 2026 18:06
@jonrohan jonrohan requested a review from a team as a code owner May 8, 2026 18:06
@jonrohan jonrohan requested review from Copilot and francinelucca May 8, 2026 18:06
@jonrohan
Copy link
Copy Markdown
Member Author

jonrohan commented May 8, 2026

@talum Is this what you had in mind for the fix for #7801

@github-actions github-actions Bot requested a deployment to storybook-preview-7824 May 8, 2026 18:10 Abandoned
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 addresses a performance issue in usePaneWidth where startTransition was being invoked on every window.resize tick even when the computed max pane width hadn’t changed, causing unnecessary concurrent React renders in SplitPageLayout/PageLayout scenarios.

Changes:

  • Added a maxPaneWidthRef and guarded the startTransition state update so it only runs when actualMax changes or when the current width must be clamped.
  • Added a unit test intended to cover the “skip redundant transition” behavior.
  • Added a Storybook performance test story to help visually confirm resize-triggered re-render behavior.
Show a summary per file
File Description
packages/react/src/PageLayout/usePaneWidth.ts Adds ref-based guarding to avoid redundant startTransition updates during resize while keeping DOM/CSS/ARIA updates unconditional.
packages/react/src/PageLayout/usePaneWidth.test.ts Adds a unit test for the new guard behavior (but currently doesn’t assert render/transition skipping directly).
packages/react/src/PageLayout/PageLayout.performance.stories.tsx Adds a Storybook “Re-render Counter (Issue #7801)” story to manually verify resize re-render behavior in DevTools.
.changeset/silent-taxis-eat.md Patch changeset entry for the performance fix.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 2

Comment on lines +892 to +894
// maxPaneWidth should be unchanged — no re-render triggered
expect(result.current.maxPaneWidth).toBe(renderCountBefore)

Comment on lines +884 to +893
// Now resize again to a different width that produces the SAME max
// 900px -> 900px (no actual viewport change, same max = 389)
const renderCountBefore = result.current.maxPaneWidth
window.dispatchEvent(new Event('resize'))
await act(async () => {
await vi.runAllTimersAsync()
})

// maxPaneWidth should be unchanged — no re-render triggered
expect(result.current.maxPaneWidth).toBe(renderCountBefore)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm staff Author is a staff member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

usePaneWidth triggers unnecessary React re-renders on every window resize

2 participants