perf(PageLayout): eliminate per-frame React renders during window resize#7847
perf(PageLayout): eliminate per-frame React renders during window resize#7847Copilot wants to merge 4 commits into
Conversation
🦋 Changeset detectedLatest commit: 71cb606 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
…PaneWidth Split syncAll() into syncDom() (DOM/refs/ARIA, called each rAF frame) and commitToReact() (single startTransition at gesture end). Replace the Date.now() throttle + rAF fallback with a single rAF coalesce — rAF already guarantees at most one call per frame, and the throttle was the source of double-fire on bursty input. The debounce callback now also calls syncDom() for a guaranteed final frame and commitToReact() for the one React commit per gesture. Add pendingMaxRef / pendingClampedRef to carry values across frames into the commit. Update test descriptions and add a new assertion that verifies zero startTransition calls during resize frames and exactly one at gesture end. Co-authored-by: mattcosta7 <8616962+mattcosta7@users.noreply.github.com>
…TimeAsync(149/1) split Use 149ms advance (flushes rAF, misses debounce) + 1ms advance (fires debounce) to clearly prove zero startTransition calls during resize and exactly one at end. Removes the nonexistent vi.runAllImmediateAsync optional-chaining guard. Co-authored-by: mattcosta7 <8616962+mattcosta7@users.noreply.github.com>
|
|
👋 Hi from github/github-ui! Your integration PR is ready: https://github.com/github/github-ui/pull/21361 |
During fast window resizing,
usePaneWidthcalledstartTransition(setState)on every throttled tick (~60 fps), stacking render requests that caused the pane DOM to visually "catch up" after the gesture ended.What changed
packages/react/src/PageLayout/usePaneWidth.tssyncAll()into two functions:syncDom()— mutates CSS custom properties (--pane-max-width,--pane-width), clampscurrentWidthRef, and updates ARIA attributes via direct DOM manipulation. Zero React state changes.commitToReact()— called exactly once at gesture end; flushes pending values into React state viastartTransitiononly if they actually changed.Date.now()throttle + rAF-fallback pattern (which could firesyncAlltwice per frame on bursty input) with a singlerequestAnimationFramecoalesce: if a rAF is already pending, new resize events are dropped until it fires.syncDom()(guaranteed final-frame sync) →commitToReact()(the one React commit for the whole gesture) →endResizeOptimizations().pendingMaxRef/pendingClampedRefto carry values across frames into the commit.packages/react/src/PageLayout/usePaneWidth.test.tsstartTransitionis called zero times while resize events are firing (pre-debounce) and exactly once when the gesture ends.Rollout strategy
Testing & Reviewing
The key behavioral invariants are unchanged —
--pane-max-width/--pane-widthCSS variables and ARIA attributes continue to track the viewport in real time; only the React state commit is deferred. The new test exercises the zero-renders-during-gesture / one-commit-at-end contract directly.Custom widths with
constrainToViewport === falsestill bail out of the resize listener early (untouched). The drag-handle path is untouched.Merge checklist