Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional initialValue argument to useDeferredValue #27500

Merged
merged 2 commits into from
Oct 10, 2023

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Oct 10, 2023

Adds a second argument to useDeferredValue called initialValue:

const value = useDeferredValue(finalValue, initialValue);

During the initial render of a component, useDeferredValue will return initialValue. Once that render finishes, it will spawn an additional render to switch to finalValue.

This same sequence should occur whenever the hook is hidden and revealed again, i.e. by a Suspense or Activity, though this part is not yet implemented.

When initialValue is not provided, useDeferredValue has no effect during initial render, but during an update, it will remain on the previous value, then spawn an additional render to switch to the new value. (This is the same behavior that exists today.)

During SSR, initialValue is always used, if provided.

This feature is currently behind an experimental flag. We plan to ship it in a non-breaking release.

Adds a new argument to useDeferredValue, `initialValue`, that is used
during initial mount, but does not implement it yet.

This is an experimental feature and is disabled in the canary build.
@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Oct 10, 2023
@react-sizebot
Copy link

react-sizebot commented Oct 10, 2023

Comparing: 77ec618...f5c6513

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js = 174.46 kB 174.46 kB = 54.27 kB 54.27 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.06% 176.31 kB 176.42 kB +0.05% 54.88 kB 54.91 kB
facebook-www/ReactDOM-prod.classic.js +0.10% 564.48 kB 565.07 kB +0.09% 99.37 kB 99.46 kB
facebook-www/ReactDOM-prod.modern.js +0.11% 548.21 kB 548.80 kB +0.10% 96.44 kB 96.54 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against f5c6513

Adds a second argument to useDeferredValue called initialValue:

```js
const value = useDeferredValue(finalValue, initialValue);
```

During the initial render of a component, useDeferredValue will return
initialValue. Once that render finishes, it will spawn an additional
render to switch to finalValue.

This same sequence should occur whenever the hook is hidden and revealed
again, i.e. by a Suspense or Activity, though this part is not yet
implemented.

When initialValue is not provided, useDeferredValue has no effect during
initial render, but during an update, it will remain on the previous
value, then spawn an additional render to switch to the new value.

During SSR, initialValue is always used, if provided.

This feature is currently behind an experimental flag. We plan to ship
it in a non-breaking release.
@acdlite acdlite merged commit be67db4 into facebook:main Oct 10, 2023
2 checks passed
github-actions bot pushed a commit that referenced this pull request Oct 10, 2023
Adds a second argument to useDeferredValue called initialValue:

```js
const value = useDeferredValue(finalValue, initialValue);
```

During the initial render of a component, useDeferredValue will return
initialValue. Once that render finishes, it will spawn an additional
render to switch to finalValue.

This same sequence should occur whenever the hook is hidden and revealed
again, i.e. by a Suspense or Activity, though this part is not yet
implemented.

When initialValue is not provided, useDeferredValue has no effect during
initial render, but during an update, it will remain on the previous
value, then spawn an additional render to switch to the new value. (This
is the same behavior that exists today.)

During SSR, initialValue is always used, if provided.

This feature is currently behind an experimental flag. We plan to ship
it in a non-breaking release.

DiffTrain build for [be67db4](be67db4)
alunyov pushed a commit to alunyov/react that referenced this pull request Oct 11, 2023
Adds a second argument to useDeferredValue called initialValue:

```js
const value = useDeferredValue(finalValue, initialValue);
```

During the initial render of a component, useDeferredValue will return
initialValue. Once that render finishes, it will spawn an additional
render to switch to finalValue.

This same sequence should occur whenever the hook is hidden and revealed
again, i.e. by a Suspense or Activity, though this part is not yet
implemented.

When initialValue is not provided, useDeferredValue has no effect during
initial render, but during an update, it will remain on the previous
value, then spawn an additional render to switch to the new value. (This
is the same behavior that exists today.)

During SSR, initialValue is always used, if provided.

This feature is currently behind an experimental flag. We plan to ship
it in a non-breaking release.
ztanner added a commit to vercel/next.js that referenced this pull request Oct 16, 2023
…experimental prefix for server action APIs (#56809)

The latest React canary builds have a few changes that need to be
adopted for compatability.

1. the `useFormState` and `useFormStatus` hooks in `react-dom` and the
`formData` opiont in `react-dom/server` are no longer prefixed with
`experimental_`
2. server content (an undocumented React feature) has been removed. Next
only had trivial intenral use of this API and did not expose a coherent
feature to Next users (no ability to seed context on refetches). It is
still possible that some users used the React server context APIs which
is why this should go into Next 14.

### React upstream changes

- facebook/react#27513
- facebook/react#27514
- facebook/react#27511
- facebook/react#27508
- facebook/react#27502
- facebook/react#27474
- facebook/react#26789
- facebook/react#27500
- facebook/react#27488
- facebook/react#27458
- facebook/react#27471
- facebook/react#27470
- facebook/react#27464
- facebook/react#27456
- facebook/react#27462
- facebook/react#27461
- facebook/react#27460
- facebook/react#27459
- facebook/react#27454
- facebook/react#27457
- facebook/react#27453
- facebook/react#27401
- facebook/react#27443
- facebook/react#27445
- facebook/react#27364
- facebook/react#27440
- facebook/react#27436

---------

Co-authored-by: Zack Tanner <zacktanner@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
acdlite added a commit to acdlite/next.js that referenced this pull request Dec 18, 2023
When PPR is enabled, there are two different versions of a segment's
data we can render: a static version (that may contain holes for the
dynamic parts) and a full version that contains everything. The static
version is prefetched before navigation, and the full version is only
loaded once the navigation occurs.

Both versions are stored on the Cache Node object. Inside LayoutRouter,
we must choose which version to render. We'll use an experimental
feature of React's `useDeferredValue` hook:
facebook/react#27500

```js
const dataToRender = useDeferredValue(fullData, prefetchedData)
```

React will coordinate when to switch from the prefetch data to the full
data. For example, if the prefetch data is unable to finish rendering
(this would happen if the segment contained dynamic data that was not
wrapped in a Suspense boundary), it knows to switch to the full data
even though the first render did not commit.
acdlite added a commit to acdlite/next.js that referenced this pull request Dec 19, 2023
When PPR is enabled, there are two different versions of a segment's
data we can render: a static version (that may contain holes for the
dynamic parts) and a full version that contains everything. The static
version is prefetched before navigation, and the full version is only
loaded once the navigation occurs.

Both versions are stored on the Cache Node object. Inside LayoutRouter,
we must choose which version to render. We'll use an experimental
feature of React's `useDeferredValue` hook:
facebook/react#27500

```js
const dataToRender = useDeferredValue(fullData, prefetchedData)
```

React will coordinate when to switch from the prefetch data to the full
data. For example, if the prefetch data is unable to finish rendering
(this would happen if the segment contained dynamic data that was not
wrapped in a Suspense boundary), it knows to switch to the full data
even though the first render did not commit.
acdlite added a commit to acdlite/next.js that referenced this pull request Dec 19, 2023
When PPR is enabled, there are two different versions of a segment's
data we can render: a static version (that may contain holes for the
dynamic parts) and a full version that contains everything. The static
version is prefetched before navigation, and the full version is only
loaded once the navigation occurs.

Both versions are stored on the Cache Node object. Inside LayoutRouter,
we must choose which version to render. We'll use an experimental
feature of React's `useDeferredValue` hook:
facebook/react#27500

```js
const dataToRender = useDeferredValue(fullData, prefetchedData)
```

React will coordinate when to switch from the prefetch data to the full
data. For example, if the prefetch data is unable to finish rendering
(this would happen if the segment contained dynamic data that was not
wrapped in a Suspense boundary), it knows to switch to the full data
even though the first render did not commit.
acdlite added a commit to acdlite/next.js that referenced this pull request Dec 19, 2023
When PPR is enabled, there are two different versions of a segment's
data we can render: a static version (that may contain holes for the
dynamic parts) and a full version that contains everything. The static
version is prefetched before navigation, and the full version is only
loaded once the navigation occurs.

Both versions are stored on the Cache Node object. Inside LayoutRouter,
we must choose which version to render. We'll use an experimental
feature of React's `useDeferredValue` hook:
facebook/react#27500

```js
const dataToRender = useDeferredValue(fullData, prefetchedData)
```

React will coordinate when to switch from the prefetch data to the full
data. For example, if the prefetch data is unable to finish rendering
(this would happen if the segment contained dynamic data that was not
wrapped in a Suspense boundary), it knows to switch to the full data
even though the first render did not commit.
acdlite added a commit to acdlite/next.js that referenced this pull request Dec 19, 2023
When PPR is enabled, there are two different versions of a segment's
data we can render: a static version (that may contain holes for the
dynamic parts) and a full version that contains everything. The static
version is prefetched before navigation, and the full version is only
loaded once the navigation occurs.

Both versions are stored on the Cache Node object. Inside LayoutRouter,
we must choose which version to render. We'll use an experimental
feature of React's `useDeferredValue` hook:
facebook/react#27500

```js
const dataToRender = useDeferredValue(fullData, prefetchedData)
```

React will coordinate when to switch from the prefetch data to the full
data. For example, if the prefetch data is unable to finish rendering
(this would happen if the segment contained dynamic data that was not
wrapped in a Suspense boundary), it knows to switch to the full data
even though the first render did not commit.
acdlite added a commit to acdlite/next.js that referenced this pull request Dec 20, 2023
When PPR is enabled, there are two different versions of a segment's
data we can render: a static version (that may contain holes for the
dynamic parts) and a full version that contains everything. The static
version is prefetched before navigation, and the full version is only
loaded once the navigation occurs.

Both versions are stored on the Cache Node object. Inside LayoutRouter,
we must choose which version to render. We'll use an experimental
feature of React's `useDeferredValue` hook:
facebook/react#27500

```js
const dataToRender = useDeferredValue(fullData, prefetchedData)
```

React will coordinate when to switch from the prefetch data to the full
data. For example, if the prefetch data is unable to finish rendering
(this would happen if the segment contained dynamic data that was not
wrapped in a Suspense boundary), it knows to switch to the full data
even though the first render did not commit.
acdlite added a commit to acdlite/react that referenced this pull request Jan 7, 2024
Fixes a bug in the experimental `initialValue` option for
`useDeferredValue` (added in facebook#27500).

If rendering the `initialValue` causes the tree to suspend, React should
skip it and switch to rendering the final value instead. It should not
wait for `initialValue` to resolve.

This is not just an optimization, because in some cases the initial
value may _never_ resolve — intentionally. For example, if the
application does not provide an instant fallback state. This capability
is, in fact, the primary motivation for the `initialValue` API.

I mostly implemented this correctly in the original PR, but I missed
some cases where it wasn't working:

- If there's no Suspense boundary between the `useDeferredValue` hook
and the component that suspends, and we're not in the shell of the
transition (i.e. there's a parent Suspense boundary wrapping the
`useDeferredValue` hook), the deferred task would get
incorrectly dropped.
- Similarly, if there's no Suspense boundary between the
`useDeferredValue` hook and the component that suspends, and we're
rendering a synchronous update, the deferred task would get incorrectly
dropped.

What these cases have in common is that it causes the `useDeferredValue`
hook itself to be replaced by a Suspense fallback. The fix was the same
for both. (It already worked in cases where there's no Suspense
fallback at all, because those are handled differently, at the root.)

The way I discovered this was when investigating a particular bug in
Next.js that would happen during a 'popstate' transition (back/forward),
but not during a regular navigation. That's because we render popstate
transitions synchronously to preserve browser's scroll position — which
in this case triggered the second scenario above.
acdlite added a commit to acdlite/react that referenced this pull request Jan 7, 2024
Fixes a bug in the experimental `initialValue` option for
`useDeferredValue` (added in facebook#27500).

If rendering the `initialValue` causes the tree to suspend, React should
skip it and switch to rendering the final value instead. It should not
wait for `initialValue` to resolve.

This is not just an optimization, because in some cases the initial
value may _never_ resolve — intentionally. For example, if the
application does not provide an instant fallback state. This capability
is, in fact, the primary motivation for the `initialValue` API.

I mostly implemented this correctly in the original PR, but I missed
some cases where it wasn't working:

- If there's no Suspense boundary between the `useDeferredValue` hook
and the component that suspends, and we're not in the shell of the
transition (i.e. there's a parent Suspense boundary wrapping the
`useDeferredValue` hook), the deferred task would get
incorrectly dropped.
- Similarly, if there's no Suspense boundary between the
`useDeferredValue` hook and the component that suspends, and we're
rendering a synchronous update, the deferred task would get incorrectly
dropped.

What these cases have in common is that it causes the `useDeferredValue`
hook itself to be replaced by a Suspense fallback. The fix was the same
for both. (It already worked in cases where there's no Suspense
fallback at all, because those are handled differently, at the root.)

The way I discovered this was when investigating a particular bug in
Next.js that would happen during a 'popstate' transition (back/forward),
but not during a regular navigation. That's because we render popstate
transitions synchronously to preserve browser's scroll position — which
in this case triggered the second scenario above.
acdlite added a commit that referenced this pull request Jan 8, 2024
… to final (#27888)

Fixes a bug in the experimental `initialValue` option for
`useDeferredValue` (added in #27500).

If rendering the `initialValue` causes the tree to suspend, React should
skip it and switch to rendering the final value instead. It should not
wait for `initialValue` to resolve.

This is not just an optimization, because in some cases the initial
value may _never_ resolve — intentionally. For example, if the
application does not provide an instant fallback state. This capability
is, in fact, the primary motivation for the `initialValue` API.

I mostly implemented this correctly in the original PR, but I missed
some cases where it wasn't working:

- If there's no Suspense boundary between the `useDeferredValue` hook
and the component that suspends, and we're not in the shell of the
transition (i.e. there's a parent Suspense boundary wrapping the
`useDeferredValue` hook), the deferred task would get incorrectly
dropped.
- Similarly, if there's no Suspense boundary between the
`useDeferredValue` hook and the component that suspends, and we're
rendering a synchronous update, the deferred task would get incorrectly
dropped.

What these cases have in common is that it causes the `useDeferredValue`
hook itself to be replaced by a Suspense fallback. The fix was the same
for both. (It already worked in cases where there's no Suspense fallback
at all, because those are handled differently, at the root.)

The way I discovered this was when investigating a particular bug in
Next.js that would happen during a 'popstate' transition (back/forward),
but not during a regular navigation. That's because we render popstate
transitions synchronously to preserve browser's scroll position — which
in this case triggered the second scenario above.
github-actions bot pushed a commit that referenced this pull request Jan 8, 2024
… to final (#27888)

Fixes a bug in the experimental `initialValue` option for
`useDeferredValue` (added in #27500).

If rendering the `initialValue` causes the tree to suspend, React should
skip it and switch to rendering the final value instead. It should not
wait for `initialValue` to resolve.

This is not just an optimization, because in some cases the initial
value may _never_ resolve — intentionally. For example, if the
application does not provide an instant fallback state. This capability
is, in fact, the primary motivation for the `initialValue` API.

I mostly implemented this correctly in the original PR, but I missed
some cases where it wasn't working:

- If there's no Suspense boundary between the `useDeferredValue` hook
and the component that suspends, and we're not in the shell of the
transition (i.e. there's a parent Suspense boundary wrapping the
`useDeferredValue` hook), the deferred task would get incorrectly
dropped.
- Similarly, if there's no Suspense boundary between the
`useDeferredValue` hook and the component that suspends, and we're
rendering a synchronous update, the deferred task would get incorrectly
dropped.

What these cases have in common is that it causes the `useDeferredValue`
hook itself to be replaced by a Suspense fallback. The fix was the same
for both. (It already worked in cases where there's no Suspense fallback
at all, because those are handled differently, at the root.)

The way I discovered this was when investigating a particular bug in
Next.js that would happen during a 'popstate' transition (back/forward),
but not during a regular navigation. That's because we render popstate
transitions synchronously to preserve browser's scroll position — which
in this case triggered the second scenario above.

DiffTrain build for [f1039be](f1039be)
acdlite added a commit to acdlite/reactjs.org that referenced this pull request Apr 10, 2024
Updates the API docs for `useDeferredValue` to include the
`initialValue` option, added in
facebook/react#27500.

This feature is slated for release in React 19.
acdlite added a commit to acdlite/react that referenced this pull request Apr 10, 2024
Per team discussion, this upgrades the `initialValue` argument for
`useDeferredValue` from experimental to canary.

- Original implementation PR: facebook#27500
- API documentation PR: reactjs/react.dev#6747
rickhanlonii pushed a commit to rickhanlonii/react.dev that referenced this pull request Apr 11, 2024
Updates the API docs for `useDeferredValue` to include the
`initialValue` option, added in
facebook/react#27500.

This feature is slated for release in React 19.
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
Adds a second argument to useDeferredValue called initialValue:

```js
const value = useDeferredValue(finalValue, initialValue);
```

During the initial render of a component, useDeferredValue will return
initialValue. Once that render finishes, it will spawn an additional
render to switch to finalValue.

This same sequence should occur whenever the hook is hidden and revealed
again, i.e. by a Suspense or Activity, though this part is not yet
implemented.

When initialValue is not provided, useDeferredValue has no effect during
initial render, but during an update, it will remain on the previous
value, then spawn an additional render to switch to the new value. (This
is the same behavior that exists today.)

During SSR, initialValue is always used, if provided.

This feature is currently behind an experimental flag. We plan to ship
it in a non-breaking release.
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
… to final (facebook#27888)

Fixes a bug in the experimental `initialValue` option for
`useDeferredValue` (added in facebook#27500).

If rendering the `initialValue` causes the tree to suspend, React should
skip it and switch to rendering the final value instead. It should not
wait for `initialValue` to resolve.

This is not just an optimization, because in some cases the initial
value may _never_ resolve — intentionally. For example, if the
application does not provide an instant fallback state. This capability
is, in fact, the primary motivation for the `initialValue` API.

I mostly implemented this correctly in the original PR, but I missed
some cases where it wasn't working:

- If there's no Suspense boundary between the `useDeferredValue` hook
and the component that suspends, and we're not in the shell of the
transition (i.e. there's a parent Suspense boundary wrapping the
`useDeferredValue` hook), the deferred task would get incorrectly
dropped.
- Similarly, if there's no Suspense boundary between the
`useDeferredValue` hook and the component that suspends, and we're
rendering a synchronous update, the deferred task would get incorrectly
dropped.

What these cases have in common is that it causes the `useDeferredValue`
hook itself to be replaced by a Suspense fallback. The fix was the same
for both. (It already worked in cases where there's no Suspense fallback
at all, because those are handled differently, at the root.)

The way I discovered this was when investigating a particular bug in
Next.js that would happen during a 'popstate' transition (back/forward),
but not during a regular navigation. That's because we render popstate
transitions synchronously to preserve browser's scroll position — which
in this case triggered the second scenario above.
acdlite added a commit that referenced this pull request Apr 16, 2024
Per team discussion, this upgrades the `initialValue` argument for
`useDeferredValue` from experimental to canary.

- Original implementation PR:
#27500
- API documentation PR: reactjs/react.dev#6747

I left it disabled at Meta for now in case there's old code somewhere
that is still passing an `options` object as the second argument.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
Adds a second argument to useDeferredValue called initialValue:

```js
const value = useDeferredValue(finalValue, initialValue);
```

During the initial render of a component, useDeferredValue will return
initialValue. Once that render finishes, it will spawn an additional
render to switch to finalValue.

This same sequence should occur whenever the hook is hidden and revealed
again, i.e. by a Suspense or Activity, though this part is not yet
implemented.

When initialValue is not provided, useDeferredValue has no effect during
initial render, but during an update, it will remain on the previous
value, then spawn an additional render to switch to the new value. (This
is the same behavior that exists today.)

During SSR, initialValue is always used, if provided.

This feature is currently behind an experimental flag. We plan to ship
it in a non-breaking release.

DiffTrain build for commit be67db4.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
… to final (#27888)

Fixes a bug in the experimental `initialValue` option for
`useDeferredValue` (added in #27500).

If rendering the `initialValue` causes the tree to suspend, React should
skip it and switch to rendering the final value instead. It should not
wait for `initialValue` to resolve.

This is not just an optimization, because in some cases the initial
value may _never_ resolve — intentionally. For example, if the
application does not provide an instant fallback state. This capability
is, in fact, the primary motivation for the `initialValue` API.

I mostly implemented this correctly in the original PR, but I missed
some cases where it wasn't working:

- If there's no Suspense boundary between the `useDeferredValue` hook
and the component that suspends, and we're not in the shell of the
transition (i.e. there's a parent Suspense boundary wrapping the
`useDeferredValue` hook), the deferred task would get incorrectly
dropped.
- Similarly, if there's no Suspense boundary between the
`useDeferredValue` hook and the component that suspends, and we're
rendering a synchronous update, the deferred task would get incorrectly
dropped.

What these cases have in common is that it causes the `useDeferredValue`
hook itself to be replaced by a Suspense fallback. The fix was the same
for both. (It already worked in cases where there's no Suspense fallback
at all, because those are handled differently, at the root.)

The way I discovered this was when investigating a particular bug in
Next.js that would happen during a 'popstate' transition (back/forward),
but not during a regular navigation. That's because we render popstate
transitions synchronously to preserve browser's scroll position — which
in this case triggered the second scenario above.

DiffTrain build for commit f1039be.
rickhanlonii added a commit to reactjs/react.dev that referenced this pull request Apr 22, 2024
* API docs for useDeferredValue's initialValue

Updates the API docs for `useDeferredValue` to include the
`initialValue` option, added in
facebook/react#27500.

This feature is slated for release in React 19.

* Add docs for onCaughtError and onUncaughtError (#6742)

* Add docs for onCaughtError and onUncaughtError

* Updates from feedback

* Add canary info, simplify a bit

---------

Co-authored-by: Ricky <rickhanlonii@fb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants