Skip to content

fix(apollo-react): stop node height flicker on handle count change [MST-11677]#867

Open
KodudulaAshishUiPath wants to merge 1 commit into
mainfrom
fix/MST-11677-basenode-height-flicker
Open

fix(apollo-react): stop node height flicker on handle count change [MST-11677]#867
KodudulaAshishUiPath wants to merge 1 commit into
mainfrom
fix/MST-11677-basenode-height-flicker

Conversation

@KodudulaAshishUiPath

@KodudulaAshishUiPath KodudulaAshishUiPath commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Problem

Deleting a case from an unconnected Switch node could make it continuously flicker between the 2-handle (96px) and 3-handle (128px) sizes. BaseNode derives node height from the visible handle count and writes it back to React Flow via updateNode.

Root cause

The write is deferred a frame via requestAnimationFrame (to avoid a synchronous effect → store-write → re-render cascade and to let React Flow's measurement settle). syncedHeightRef — the "last height we wrote", used by a render-time guard to keep our own handle-inflation writes out of baseHeightRef — was being stamped at schedule time (effect body) rather than commit time. That opened a one-frame window where a stale in-flight height was misread as an external resize, poisoning baseHeightRef and driving the 96px↔128px loop.

Demo

Screen.Recording.2026-06-30.at.00.02.48.mov

Tests

Adds a regression test (Height computation (deferred rAF race)) that keeps the rAF deferred to expose the schedule-vs-commit window, removes a handle with an interleaved stale render, and asserts the node deflates to 96 and settles without bouncing back to 128. Verified it fails on the unfixed code and passes with the fix. Full apollo-react suite green (1884 tests).

Copilot AI review requested due to automatic review settings June 29, 2026 18:39
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Review Updated (PT)
apollo-design 🟢 Ready Preview, Logs Jun 29, 2026, 11:43:42 AM
apollo-docs 🟢 Ready Preview, Logs Jun 29, 2026, 11:43:42 AM
apollo-landing 🟢 Ready Preview, Logs Jun 29, 2026, 11:43:42 AM
apollo-vertex 🟢 Ready Preview, Logs Jun 29, 2026, 11:43:42 AM

@github-actions

Copy link
Copy Markdown
Contributor

Dependency License Review

  • 1945 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1715
ISC 89
Apache-2.0 55
BSD-3-Clause 27
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
MIT-0 3
CC0-1.0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.2.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes a React Flow node-height oscillation in apollo-react canvas BaseNode caused by a deferred requestAnimationFrame height sync briefly stamping a “synced” height before the write actually committed, allowing a stale in-flight height to be treated as an external resize.

Changes:

  • Move syncedHeightRef stamping into the rAF callback so it only records heights that were actually committed via updateNode.
  • Tighten comments around syncedHeightRef / baseHeightRef semantics to reflect commit-time stamping and the external-vs-internal height distinction.
  • Add a regression test that keeps rAF deferred and reproduces the stale interleaved render scenario, asserting the node deflates and remains stable.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/apollo-react/src/canvas/components/BaseNode/BaseNode.tsx Stamps syncedHeightRef at rAF commit time (paired with updateNode) to prevent stale in-flight heights from poisoning baseHeightRef.
packages/apollo-react/src/canvas/components/BaseNode/BaseNode.test.tsx Adds a deferred-rAF regression test to reproduce and prevent the 96px ↔ 128px flicker loop.

@github-actions

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core 9.0% 43.82 MB 57.31 MB ±0
@uipath/apollo-react 34.7% 100.0% (1/1) 7.27 MB 27.59 MB ±0
@uipath/apollo-wind 40.1% 392.4 KB 2.55 MB −9 B
@uipath/ap-chat 85.8% 43.41 MB 55.85 MB ±0

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

const frameId = requestAnimationFrame(() => {
// Stamp at commit time, paired with the write, so the guard above never
// mistakes an in-flight stale height for an external resize.
syncedHeightRef.current = computedHeight;

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.

[P1] This can still bounce back to the stale height if another render lands after this rAF stamps syncedHeightRef but before React Flow propagates the new height prop. In that window, the guard above treats the stale height as an external resize, restores baseHeightRef to the old value, and schedules the old height again.

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.

Suggested change:
Keep the previous synced height ignored until that same value is observed through props, or track a separate pending synced target/source pair so stale post-commit renders cannot rewrite baseHeightRef. Please also add coverage for a stale rerender after the rAF callback fires and before the new height prop arrives.

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

Labels

pkg:apollo-react size:M 30-99 changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants