feat: implement getServerSnapshot for useSyncExternalStore - #4979
Conversation
📊 Tachometer Benchmark ResultsSummary⏳ Benchmarks are currently running. Results below are out of date. duration
usedJSHeapSize
Results⏳ Benchmarks are currently running. Results below are out of date. create10kduration
usedJSHeapSize
filter-listduration
usedJSHeapSize
hydrate1kduration
usedJSHeapSize
many-updatesduration
usedJSHeapSize
replace1kduration
usedJSHeapSize
run-warmup-0
run-warmup-1
run-warmup-2
run-warmup-3
run-warmup-4
run-final
text-updateduration
usedJSHeapSize
tododuration
usedJSHeapSize
update10th1kduration
usedJSHeapSize
|
Co-Authored-By: rschristian <rschristian@users.noreply.github.com>
Co-Authored-By: rschristian <rschristian@users.noreply.github.com>
| getServerSnapshot | ||
| ) { | ||
| const value = | ||
| typeof window === 'undefined' || hydrating |
There was a problem hiding this comment.
This or we use options._skipEffects
| typeof window === 'undefined' || hydrating | ||
| ? getServerSnapshot | ||
| ? getServerSnapshot() | ||
| : missingGetServerSnapshot() |
There was a problem hiding this comment.
Let's not add oversized error strings, this seems a bit against our bundle philosophy
There was a problem hiding this comment.
That (the oversized string) was my suggestion FWIW, my bad
| let oldBeforeRender = options._render; | ||
|
|
||
| /** @type {(vnode: import('./internal').VNode) => void} */ | ||
| options._render = _vnode => { |
There was a problem hiding this comment.
If we move this to the render.js file you can benefit from options._render there and save more bytes
There was a problem hiding this comment.
Having hooks.js only contain some hooks, not all, is kinda weird... what was the byte difference there, if you remember? Should we even keep this module around, or should it be inlined into render?
There was a problem hiding this comment.
When I tried it locally it was 32b gzip
There was a problem hiding this comment.
Roughly a third then, hefty.
JoviDeCroock
left a comment
There was a problem hiding this comment.
The general trend of this looks good, left some comments on how to reduce bundle size. Let's get this into v11
|
@JoviDeCroock Thank you for the review! I've made the changes, so please take a look. |
|
I meant move the whole hook over 😅 this made the byte size regress |
| ) { | ||
| const serverRendering = options._skipEffects || hydrationRoot; | ||
| if (serverRendering && !getServerSnapshot) { | ||
| throw new Error('Missing getServerSnapshot'); |
There was a problem hiding this comment.
Remove the error all together imho, we can just fall back to regular snapshot.
There was a problem hiding this comment.
I will make that change as suggested!
Please note that React throws an error in this case.
If you omit this argument, rendering the component on the server will throw an error.
JoviDeCroock
left a comment
There was a problem hiding this comment.
Thank you for implementing this!
The getServerSnapshot test added in #4979 asserts React's effect ordering during hydration: the passive effect runs once for the server snapshot and once for the client snapshot. It got that ordering from the stale-effect flush in options._render that this branch removes. That flush is no longer how pending effects are drained -- the scheduler installed by preact/hooks flushes them before a scheduled render instead. `act` replaces options.debounceRendering, so it bypasses that scheduler and drains renders before effects. Run the test on the default scheduler, like the suspense and useSyncExternalStore bail-out tests on this branch already do; the assertions are unchanged and still match React.
close #4972