Skip to content

Stabilize useId with named Suspense boundaries#5156

Open
JoviDeCroock wants to merge 1 commit into
v10.xfrom
JoviDeCroock/resumed-hydration-useid-fix
Open

Stabilize useId with named Suspense boundaries#5156
JoviDeCroock wants to merge 1 commit into
v10.xfrom
JoviDeCroock/resumed-hydration-useid-fix

Conversation

@JoviDeCroock

Copy link
Copy Markdown
Member

Summary

  • add an optional name prop to Suspense
  • use the name as a stable useId namespace for resumed hydration
  • cover opposite async resolution orders and client-only work appearing during hydration

Background

#5108 assigned a numeric namespace to each Suspense boundary as it rendered. That kept sibling boundaries stable when they resolved in different orders, but the namespace still depended on render order. As described in #5135, client-only work could render during hydration and consume the namespace that a later server-rendered boundary expected, shifting its generated ids.

A named boundary no longer participates in that shared allocation order. Its name deterministically seeds the namespace on both the server and client, and the namespace is retained on the component when its VNode is replaced. Unnamed boundaries keep their existing behavior.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

📊 Tachometer Benchmark Results

Summary

duration

  • create10k: unsure 🔍 -1% - +1% (-4.52ms - +3.66ms)
    preact-local vs preact-main
  • filter-list: unsure 🔍 -1% - +1% (-0.25ms - +0.17ms)
    preact-local vs preact-main
  • hydrate1k: unsure 🔍 -3% - +2% (-1.11ms - +0.81ms)
    preact-local vs preact-main
  • many-updates: unsure 🔍 -0% - +0% (-0.05ms - +0.01ms)
    preact-local vs preact-main
  • replace1k: unsure 🔍 -2% - +1% (-0.95ms - +0.82ms)
    preact-local vs preact-main
  • text-update: unsure 🔍 -5% - +4% (-0.09ms - +0.08ms)
    preact-local vs preact-main
  • todo: unsure 🔍 -1% - +2% (-0.38ms - +0.53ms)
    preact-local vs preact-main
  • update10th1k: unsure 🔍 -4% - +5% (-1.33ms - +1.74ms)
    preact-local vs preact-main

usedJSHeapSize

  • create10k: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • filter-list: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • hydrate1k: unsure 🔍 -5% - +2% (-0.25ms - +0.11ms)
    preact-local vs preact-main
  • many-updates: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • replace1k: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • text-update: unsure 🔍 -4% - +2% (-0.04ms - +0.02ms)
    preact-local vs preact-main
  • todo: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • update10th1k: unsure 🔍 -0% - +0% (-0.01ms - +0.01ms)
    preact-local vs preact-main

Results

create10k

duration

VersionAvg timevs preact-localvs preact-main
preact-local691.96ms - 697.38ms-unsure 🔍
-1% - +1%
-4.52ms - +3.66ms
preact-main692.04ms - 698.17msunsure 🔍
-1% - +1%
-3.66ms - +4.52ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local19.21ms - 19.21ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main19.21ms - 19.21msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
filter-list

duration

VersionAvg timevs preact-localvs preact-main
preact-local16.54ms - 16.75ms-unsure 🔍
-1% - +1%
-0.25ms - +0.17ms
preact-main16.50ms - 16.87msunsure 🔍
-1% - +2%
-0.17ms - +0.25ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local1.56ms - 1.57ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main1.56ms - 1.57msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
hydrate1k

duration

VersionAvg timevs preact-localvs preact-main
preact-local39.35ms - 40.69ms-unsure 🔍
-3% - +2%
-1.11ms - +0.81ms
preact-main39.48ms - 40.85msunsure 🔍
-2% - +3%
-0.81ms - +1.11ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local5.00ms - 5.21ms-unsure 🔍
-5% - +2%
-0.25ms - +0.11ms
preact-main5.03ms - 5.32msunsure 🔍
-2% - +5%
-0.11ms - +0.25ms
-
many-updates

duration

VersionAvg timevs preact-localvs preact-main
preact-local16.53ms - 16.57ms-unsure 🔍
-0% - +0%
-0.05ms - +0.01ms
preact-main16.54ms - 16.59msunsure 🔍
-0% - +0%
-0.01ms - +0.05ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local3.73ms - 3.73ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main3.73ms - 3.73msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
replace1k
  • Browser: chrome-headless
  • Sample size: 100
  • Built by: CI #5661
  • Commit: 3ceee63

duration

VersionAvg timevs preact-localvs preact-main
preact-local57.19ms - 58.39ms-unsure 🔍
-2% - +1%
-0.95ms - +0.82ms
preact-main57.20ms - 58.51msunsure 🔍
-1% - +2%
-0.82ms - +0.95ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local3.02ms - 3.02ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main3.02ms - 3.02msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-

run-warmup-0

VersionAvg timevs preact-localvs preact-main
preact-local27.93ms - 28.81ms-unsure 🔍
-2% - +2%
-0.49ms - +0.70ms
preact-main27.87ms - 28.67msunsure 🔍
-2% - +2%
-0.70ms - +0.49ms
-

run-warmup-1

VersionAvg timevs preact-localvs preact-main
preact-local32.39ms - 33.37ms-slower ❌
1% - 5%
0.29ms - 1.58ms
preact-main31.53ms - 32.36msfaster ✔
1% - 5%
0.29ms - 1.58ms
-

run-warmup-2

VersionAvg timevs preact-localvs preact-main
preact-local32.48ms - 33.77ms-unsure 🔍
-1% - +4%
-0.32ms - +1.36ms
preact-main32.07ms - 33.14msunsure 🔍
-4% - +1%
-1.36ms - +0.32ms
-

run-warmup-3

VersionAvg timevs preact-localvs preact-main
preact-local26.56ms - 27.18ms-unsure 🔍
-1% - +2%
-0.29ms - +0.53ms
preact-main26.48ms - 27.02msunsure 🔍
-2% - +1%
-0.53ms - +0.29ms
-

run-warmup-4

VersionAvg timevs preact-localvs preact-main
preact-local22.21ms - 23.25ms-faster ✔
2% - 8%
0.34ms - 1.91ms
preact-main23.27ms - 24.44msslower ❌
1% - 8%
0.34ms - 1.91ms
-

run-final

VersionAvg timevs preact-localvs preact-main
preact-local21.24ms - 21.62ms-unsure 🔍
-2% - +1%
-0.34ms - +0.20ms
preact-main21.30ms - 21.69msunsure 🔍
-1% - +2%
-0.20ms - +0.34ms
-
text-update
  • Browser: chrome-headless
  • Sample size: 230
  • Built by: CI #5661
  • Commit: 3ceee63

duration

VersionAvg timevs preact-localvs preact-main
preact-local1.95ms - 2.07ms-unsure 🔍
-5% - +4%
-0.09ms - +0.08ms
preact-main1.96ms - 2.08msunsure 🔍
-4% - +5%
-0.08ms - +0.09ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local1.01ms - 1.05ms-unsure 🔍
-4% - +2%
-0.04ms - +0.02ms
preact-main1.02ms - 1.07msunsure 🔍
-2% - +4%
-0.02ms - +0.04ms
-
todo

duration

VersionAvg timevs preact-localvs preact-main
preact-local34.60ms - 35.23ms-unsure 🔍
-1% - +2%
-0.38ms - +0.53ms
preact-main34.51ms - 35.16msunsure 🔍
-2% - +1%
-0.53ms - +0.38ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local1.26ms - 1.26ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main1.26ms - 1.26msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
update10th1k

duration

VersionAvg timevs preact-localvs preact-main
preact-local36.29ms - 38.29ms-unsure 🔍
-4% - +5%
-1.33ms - +1.74ms
preact-main35.92ms - 38.24msunsure 🔍
-5% - +4%
-1.74ms - +1.33ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local2.98ms - 3.00ms-unsure 🔍
-0% - +0%
-0.01ms - +0.01ms
preact-main2.98ms - 3.00msunsure 🔍
-0% - +0%
-0.01ms - +0.01ms
-

tachometer-reporter-action v2 for CI

@github-actions

Copy link
Copy Markdown

Size Change: +108 B (+0.14%)

Total Size: 79.6 kB

📦 View Changed
Filename Size Change
compat/dist/compat.js 4.22 kB +28 B (+0.67%)
compat/dist/compat.mjs 4.13 kB +25 B (+0.61%)
compat/dist/compat.module.js 4.13 kB +25 B (+0.61%)
compat/dist/compat.umd.js 4.29 kB +30 B (+0.71%)
ℹ️ View Unchanged
Filename Size
debug/dist/debug.js 3.85 kB
debug/dist/debug.mjs 3.85 kB
debug/dist/debug.module.js 3.85 kB
debug/dist/debug.umd.js 3.93 kB
devtools/dist/devtools.js 260 B
devtools/dist/devtools.mjs 274 B
devtools/dist/devtools.module.js 274 B
devtools/dist/devtools.umd.js 346 B
dist/preact.js 4.83 kB
dist/preact.min.js 4.84 kB
dist/preact.min.module.js 4.85 kB
dist/preact.min.umd.js 4.86 kB
dist/preact.mjs 4.85 kB
dist/preact.module.js 4.85 kB
dist/preact.umd.js 4.87 kB
hooks/dist/hooks.js 1.51 kB
hooks/dist/hooks.mjs 1.54 kB
hooks/dist/hooks.module.js 1.54 kB
hooks/dist/hooks.umd.js 1.58 kB
jsx-runtime/dist/jsxRuntime.js 1.01 kB
jsx-runtime/dist/jsxRuntime.mjs 985 B
jsx-runtime/dist/jsxRuntime.module.js 985 B
jsx-runtime/dist/jsxRuntime.umd.js 1.08 kB
test-utils/dist/testUtils.js 473 B
test-utils/dist/testUtils.mjs 477 B
test-utils/dist/testUtils.module.js 477 B
test-utils/dist/testUtils.umd.js 555 B

compressed-size-action

@JoviDeCroock JoviDeCroock marked this pull request as ready for review July 16, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant