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

Implement experimental_useOptimisticState #26740

Merged
merged 3 commits into from
May 1, 2023

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Apr 28, 2023

This adds an experimental hook tentatively called useOptimisticState. (The actual name needs some bikeshedding.)

The headline feature is that you can use it to implement optimistic updates. If you set some optimistic state during a transition/action, the state will be automatically reverted once the transition completes.

Another feature is that the optimistic updates will be continually rebased on top of the latest state.

It's easiest to explain with examples; we'll publish documentation as the API gets closer to stabilizing. See tests for now.

Technically the use cases for this hook are broader than just optimistic updates; you could use it implement any sort of "pending" state, such as the ones exposed by useTransition and useFormStatus. But we expect people will most often reach for this hook to implement the optimistic update pattern; simpler cases are covered by those other hooks.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Apr 28, 2023
@react-sizebot
Copy link

react-sizebot commented Apr 28, 2023

Comparing: b12bea6...4b11d7b

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 +0.07% 164.05 kB 164.17 kB +0.09% 51.73 kB 51.77 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.62% 170.35 kB 171.41 kB +0.55% 53.64 kB 53.93 kB
facebook-www/ReactDOM-prod.classic.js +0.62% 567.08 kB 570.62 kB +0.51% 100.17 kB 100.68 kB
facebook-www/ReactDOM-prod.modern.js +0.64% 550.81 kB 554.35 kB +0.53% 97.37 kB 97.89 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-art/cjs/react-art.development.js +1.13% 813.50 kB 822.66 kB +0.91% 177.27 kB 178.89 kB
oss-experimental/react-art/cjs/react-art.production.min.js +1.12% 97.21 kB 98.30 kB +0.91% 29.89 kB 30.16 kB
facebook-www/ReactART-dev.modern.js +1.08% 901.42 kB 911.13 kB +0.91% 192.36 kB 194.11 kB
facebook-www/ReactART-dev.classic.js +1.06% 912.62 kB 922.34 kB +0.90% 194.65 kB 196.41 kB
oss-experimental/react/cjs/react.production.min.js +1.06% 9.08 kB 9.17 kB +0.62% 3.40 kB 3.42 kB
facebook-www/ReactART-prod.modern.js +1.06% 335.03 kB 338.57 kB +0.85% 57.04 kB 57.53 kB
oss-experimental/react-art/umd/react-art.development.js +1.03% 928.93 kB 938.50 kB +0.84% 196.28 kB 197.93 kB
facebook-www/ReactART-prod.classic.js +1.02% 346.03 kB 349.56 kB +0.82% 58.96 kB 59.44 kB
oss-experimental/react-reconciler/cjs/react-reconciler.development.js +1.00% 914.22 kB 923.40 kB +0.85% 195.70 kB 197.37 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.min.js +0.92% 114.43 kB 115.49 kB +0.68% 35.03 kB 35.27 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.min.js +0.86% 123.44 kB 124.51 kB +0.73% 37.21 kB 37.48 kB
facebook-www/React-prod.modern.js +0.82% 21.15 kB 21.32 kB +0.70% 5.27 kB 5.31 kB
facebook-react-native/react/cjs/React-prod.js +0.82% 21.18 kB 21.35 kB +0.72% 5.31 kB 5.35 kB
oss-experimental/react-art/umd/react-art.production.min.js +0.81% 134.47 kB 135.56 kB +0.63% 42.06 kB 42.33 kB
facebook-www/React-prod.classic.js +0.81% 21.44 kB 21.62 kB +0.67% 5.35 kB 5.39 kB
facebook-react-native/react/cjs/React-profiling.js +0.81% 21.49 kB 21.66 kB +0.75% 5.36 kB 5.40 kB
facebook-www/React-profiling.modern.js +0.80% 21.76 kB 21.93 kB +0.68% 5.40 kB 5.44 kB
facebook-www/React-profiling.classic.js +0.78% 22.05 kB 22.22 kB +0.66% 5.48 kB 5.51 kB
oss-experimental/react-dom/cjs/react-dom.development.js +0.71% 1,296.73 kB 1,305.91 kB +0.58% 286.80 kB 288.47 kB
oss-experimental/react-dom/umd/react-dom.development.js +0.71% 1,359.53 kB 1,369.12 kB +0.58% 289.66 kB 291.33 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.development.js +0.70% 1,314.79 kB 1,323.97 kB +0.57% 291.11 kB 292.77 kB
oss-experimental/react/umd/react.profiling.min.js +0.70% 12.90 kB 12.99 kB +0.38% 4.97 kB 4.99 kB
oss-experimental/react/umd/react.production.min.js +0.70% 12.90 kB 12.99 kB +0.38% 4.96 kB 4.98 kB
facebook-www/ReactDOM-dev.modern.js +0.69% 1,403.85 kB 1,413.56 kB +0.59% 303.55 kB 305.33 kB
facebook-www/ReactDOMTesting-dev.modern.js +0.68% 1,422.19 kB 1,431.91 kB +0.59% 307.95 kB 309.77 kB
facebook-www/ReactDOM-dev.classic.js +0.68% 1,431.74 kB 1,441.46 kB +0.59% 308.99 kB 310.81 kB
facebook-www/ReactDOMTesting-dev.classic.js +0.67% 1,450.09 kB 1,459.80 kB +0.57% 313.45 kB 315.23 kB
facebook-www/ReactDOM-prod.modern.js +0.64% 550.81 kB 554.35 kB +0.53% 97.37 kB 97.89 kB
facebook-www/ReactDOM-prod.classic.js +0.62% 567.08 kB 570.62 kB +0.51% 100.17 kB 100.68 kB
facebook-www/ReactDOMTesting-prod.modern.js +0.62% 567.35 kB 570.89 kB +0.49% 101.47 kB 101.96 kB
facebook-www/ReactDOM-profiling.modern.js +0.62% 581.23 kB 584.83 kB +0.51% 101.83 kB 102.35 kB
oss-experimental/react-dom/umd/react-dom.production.min.js +0.62% 170.19 kB 171.24 kB +0.45% 53.95 kB 54.19 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.62% 170.35 kB 171.41 kB +0.55% 53.64 kB 53.93 kB
facebook-www/ReactDOMTesting-prod.classic.js +0.61% 581.90 kB 585.43 kB +0.49% 103.88 kB 104.39 kB
facebook-www/ReactDOM-profiling.classic.js +0.60% 597.57 kB 601.17 kB +0.48% 104.64 kB 105.15 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.min.js +0.60% 176.56 kB 177.62 kB +0.48% 55.98 kB 56.25 kB
oss-experimental/react-dom/umd/react-dom.profiling.min.js +0.59% 179.17 kB 180.24 kB +0.45% 56.29 kB 56.54 kB
oss-experimental/react-dom/cjs/react-dom.profiling.min.js +0.59% 179.98 kB 181.04 kB +0.48% 56.06 kB 56.33 kB
oss-experimental/react-server/cjs/react-server.production.min.js +0.51% 25.10 kB 25.23 kB +0.50% 8.57 kB 8.61 kB
oss-experimental/react/cjs/react.development.js +0.28% 101.38 kB 101.66 kB +0.16% 27.37 kB 27.41 kB
facebook-react-native/react/cjs/React-dev.js +0.23% 119.84 kB 120.13 kB +0.17% 31.55 kB 31.61 kB
oss-experimental/react/umd/react.development.js +0.23% 125.01 kB 125.30 kB +0.17% 32.24 kB 32.30 kB
oss-experimental/react-server/cjs/react-server.development.js +0.22% 146.83 kB 147.16 kB +0.15% 36.66 kB 36.71 kB
facebook-www/React-dev.modern.js +0.22% 126.47 kB 126.75 kB +0.14% 33.41 kB 33.46 kB
facebook-www/React-dev.classic.js +0.22% 127.56 kB 127.84 kB +0.15% 33.65 kB 33.70 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.production.min.js +0.20% 63.31 kB 63.44 kB +0.22% 19.08 kB 19.13 kB

Generated by 🚫 dangerJS against 4b11d7b

@acdlite acdlite force-pushed the useoptimisticstate branch 2 times, most recently from 5088abf to 5ae1864 Compare April 28, 2023 19:35
@acdlite acdlite marked this pull request as ready for review April 28, 2023 19:35
@unstubbable
Copy link
Contributor

unstubbable commented Apr 28, 2023

That’s a nice addition to the hooks family! ❤️ Also, for what it’s worth, ChatGPT agrees with the name:

41BA6D45-9BBF-41E2-AF8C-A42426ABCFDF

@acdlite acdlite force-pushed the useoptimisticstate branch 2 times, most recently from c53e4aa to 47d8a5b Compare April 28, 2023 20:27

updaterFn = () => {
startTransition(() => {
React.startTransition(() => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This test needed to be updated because the lane changed from Continuous (which we're merging with Sync soon regardless) to Sync but since it doesn't really test anything specific to the hook form of startTransition I switched it to use the non-hook form instead, which doesn't perform a pending update. That way the test works when running against older versions of React, too.

Small refactor to startTransition so that it calls setState directly
instead of a bound setState method passed to it from the caller.
@acdlite acdlite force-pushed the useoptimisticstate branch 2 times, most recently from 5aa9b2f to b63f772 Compare April 29, 2023 15:13
@@ -423,6 +424,10 @@ export type Dispatcher = {
useCacheRefresh?: () => <T>(?() => T, ?T) => void,
useMemoCache?: (size: number) => Array<any>,

Choose a reason for hiding this comment

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

useMemoCache?: (size: number) => Array

newBaseQueueLast = newBaseQueueLast.next = clone;
// Check if this is an optimistic update.
const revertLane = update.revertLane;
if (revertLane === NoLane) {
Copy link
Collaborator

@sebmarkbage sebmarkbage May 1, 2023

Choose a reason for hiding this comment

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

Should probably gate this:

Suggested change
if (revertLane === NoLane) {
if (!enableAsyncActions || revertLane === NoLane) {

This adds an experimental hook tentatively called useOptimisticState.
(The actual name needs some bikeshedding.)

The headline feature is that you can use it to implement optimistic
updates. If you set some optimistic state during a transition/action,
the state will be automatically reverted once the transition completes.

Another feature is that the optimistic updates will be continually
rebased on top of the latest state.

It's easiest to explain with examples; we'll publish documentation as
the API gets closer to stabilizing. See tests for now.

Technically the use cases for this hook are broader than just optimistic
updates; you could use it implement any sort of "pending" state, such
as the ones exposed by useTransition and useFormStatus. But we expect
people will most often reach for this hook to implement the optimistic
update pattern; simpler cases are covered by those other hooks.
@acdlite acdlite merged commit 491aec5 into facebook:main May 1, 2023
github-actions bot pushed a commit that referenced this pull request May 1, 2023
This adds an experimental hook tentatively called useOptimisticState.
(The actual name needs some bikeshedding.)

The headline feature is that you can use it to implement optimistic
updates. If you set some optimistic state during a transition/action,
the state will be automatically reverted once the transition completes.

Another feature is that the optimistic updates will be continually
rebased on top of the latest state.

It's easiest to explain with examples; we'll publish documentation as
the API gets closer to stabilizing. See tests for now.

Technically the use cases for this hook are broader than just optimistic
updates; you could use it implement any sort of "pending" state, such as
the ones exposed by useTransition and useFormStatus. But we expect
people will most often reach for this hook to implement the optimistic
update pattern; simpler cases are covered by those other hooks.

DiffTrain build for [491aec5](491aec5)
acdlite added a commit to acdlite/next.js that referenced this pull request May 3, 2023
Includes the following upstream changes:

- [5dd90c562](https://github.com/facebook/react/commits/5dd90c562) Use content hash for react-native builds ([vercel#26734](facebook/react#26734)) (Samuel Susla)
- [559e83aeb](https://github.com/facebook/react/commits/559e83aeb) [Fizz] Allow an action provide a custom set of props to use for progressive enhancement ([vercel#26749](facebook/react#26749)) (Sebastian Markbåge)
- [67f4fb021](https://github.com/facebook/react/commits/67f4fb021) Allow forms to skip hydration of hidden inputs ([vercel#26735](facebook/react#26735)) (Sebastian Markbåge)
- [8ea96ef84](https://github.com/facebook/react/commits/8ea96ef84) [Fizz] Encode external fizz runtime into chunks eagerly ([vercel#26752](facebook/react#26752)) (Josh Story)
- [491aec5d6](https://github.com/facebook/react/commits/491aec5d6) Implement experimental_useOptimisticState ([vercel#26740](facebook/react#26740)) (Andrew Clark)
- [9545e4810](https://github.com/facebook/react/commits/9545e4810) Add nonce support to bootstrap scripts and external runtime ([vercel#26738](facebook/react#26738)) (Dan Ott)
- [86b0e9199](https://github.com/facebook/react/commits/86b0e9199) Gate DevTools test to fix CI ([#26742](facebook/react#26742)) (Andrew Clark)
- [b12bea62d](https://github.com/facebook/react/commits/b12bea62d) Preinits should support a nonce option ([#26744](facebook/react#26744)) (Josh Story)
- [efbd68511](https://github.com/facebook/react/commits/efbd68511) Remove unused `initialStatus` parameter from `useHostTransitionStatus` ([vercel#26743](facebook/react#26743)) (Sebastian Silbermann)
- [18282f881](https://github.com/facebook/react/commits/18282f881) Fix: Update while suspended fails to interrupt ([vercel#26739](facebook/react#26739)) (Andrew Clark)
- [540bab085](https://github.com/facebook/react/commits/540bab085) Implement experimental_useFormStatus ([#26722](facebook/react#26722)) (Andrew Clark)
acdlite added a commit to acdlite/next.js that referenced this pull request May 3, 2023
Includes the following upstream changes:

- [5dd90c562](https://github.com/facebook/react/commits/5dd90c562) Use content hash for react-native builds ([vercel#26734](facebook/react#26734)) (Samuel Susla)
- [559e83aeb](https://github.com/facebook/react/commits/559e83aeb) [Fizz] Allow an action provide a custom set of props to use for progressive enhancement ([vercel#26749](facebook/react#26749)) (Sebastian Markbåge)
- [67f4fb021](https://github.com/facebook/react/commits/67f4fb021) Allow forms to skip hydration of hidden inputs ([vercel#26735](facebook/react#26735)) (Sebastian Markbåge)
- [8ea96ef84](https://github.com/facebook/react/commits/8ea96ef84) [Fizz] Encode external fizz runtime into chunks eagerly ([vercel#26752](facebook/react#26752)) (Josh Story)
- [491aec5d6](https://github.com/facebook/react/commits/491aec5d6) Implement experimental_useOptimisticState ([vercel#26740](facebook/react#26740)) (Andrew Clark)
- [9545e4810](https://github.com/facebook/react/commits/9545e4810) Add nonce support to bootstrap scripts and external runtime ([vercel#26738](facebook/react#26738)) (Dan Ott)
- [86b0e9199](https://github.com/facebook/react/commits/86b0e9199) Gate DevTools test to fix CI ([#26742](facebook/react#26742)) (Andrew Clark)
- [b12bea62d](https://github.com/facebook/react/commits/b12bea62d) Preinits should support a nonce option ([#26744](facebook/react#26744)) (Josh Story)
- [efbd68511](https://github.com/facebook/react/commits/efbd68511) Remove unused `initialStatus` parameter from `useHostTransitionStatus` ([vercel#26743](facebook/react#26743)) (Sebastian Silbermann)
- [18282f881](https://github.com/facebook/react/commits/18282f881) Fix: Update while suspended fails to interrupt ([vercel#26739](facebook/react#26739)) (Andrew Clark)
- [540bab085](https://github.com/facebook/react/commits/540bab085) Implement experimental_useFormStatus ([#26722](facebook/react#26722)) (Andrew Clark)
ijjk pushed a commit to vercel/next.js that referenced this pull request May 3, 2023
Includes the following upstream changes:

- [b7972822b](https://github.com/facebook/react/commits/b7972822b)
useOptimisticState -> useOptimistic
([#26772](facebook/react#26772)) (Andrew Clark)
- [388686f29](https://github.com/facebook/react/commits/388686f29) Add
"canary" to list of allowed npm dist tags
([#26767](facebook/react#26767)) (Andrew Clark)
- [8a25302c6](https://github.com/facebook/react/commits/8a25302c6)
fix[dynamic-scripts-injection]: unregister content scripts before
registration ([#26765](facebook/react#26765))
(Ruslan Lesiutin)
- [2c2476834](https://github.com/facebook/react/commits/2c2476834)
Rename "next" prerelease channel to "canary"
([#26761](facebook/react#26761)) (Andrew Clark)
- [fa4314841](https://github.com/facebook/react/commits/fa4314841)
Remove deprecated workflow key from Circle config
([#26762](facebook/react#26762)) (Andrew Clark)
- [5dd90c562](https://github.com/facebook/react/commits/5dd90c562) Use
content hash for react-native builds
([#26734](facebook/react#26734)) (Samuel Susla)
- [559e83aeb](https://github.com/facebook/react/commits/559e83aeb)
[Fizz] Allow an action provide a custom set of props to use for
progressive enhancement
([#26749](facebook/react#26749)) (Sebastian
Markbåge)
- [67f4fb021](https://github.com/facebook/react/commits/67f4fb021) Allow
forms to skip hydration of hidden inputs
([#26735](facebook/react#26735)) (Sebastian
Markbåge)
- [8ea96ef84](https://github.com/facebook/react/commits/8ea96ef84)
[Fizz] Encode external fizz runtime into chunks eagerly
([#26752](facebook/react#26752)) (Josh Story)
- [491aec5d6](https://github.com/facebook/react/commits/491aec5d6)
Implement experimental_useOptimisticState
([#26740](facebook/react#26740)) (Andrew Clark)
- [9545e4810](https://github.com/facebook/react/commits/9545e4810) Add
nonce support to bootstrap scripts and external runtime
([#26738](facebook/react#26738)) (Dan Ott)
- [86b0e9199](https://github.com/facebook/react/commits/86b0e9199) Gate
DevTools test to fix CI
([#26742](facebook/react#26742)) (Andrew Clark)
- [b12bea62d](https://github.com/facebook/react/commits/b12bea62d)
Preinits should support a nonce option
([#26744](facebook/react#26744)) (Josh Story)
- [efbd68511](https://github.com/facebook/react/commits/efbd68511)
Remove unused `initialStatus` parameter from `useHostTransitionStatus`
([#26743](facebook/react#26743)) (Sebastian
Silbermann)
- [18282f881](https://github.com/facebook/react/commits/18282f881) Fix:
Update while suspended fails to interrupt
([#26739](facebook/react#26739)) (Andrew Clark)
- [540bab085](https://github.com/facebook/react/commits/540bab085)
Implement experimental_useFormStatus
([#26722](facebook/react#26722)) (Andrew Clark)

---------
hoxyq added a commit that referenced this pull request Sep 21, 2023
…etermining if hook is stateful (#27365)

#26740 introduced regression:
React DevTools doesn't record updates for `useTransition` hook. I can
add more details about things on DevTools side, if needed.

The root cause is
https://github.com/facebook/react/blob/491aec5d6113ce5bae7c10966bc38a4a8fc091a8/packages/react-reconciler/src/ReactFiberHooks.js#L2728-L2730

React DevTools expects dispatch to be present for stateful hooks that
can schedule an update -
https://github.com/facebook/react/blob/2eed1328478e8c923fcb4e6abf5efbd9e1233402/packages/react-devtools-shared/src/backend/renderer.js#L1422-L1428

With these changes, we still call dispatch in `startTransition`, but
also patch `queue` object with it, so that React DevTools can recognise
`useTransition` as stateful hook that can schedule update.

I am not sure if this is the right approach to fix this, can we
distinguish if `startTransition` was called from `useTransition` hook or
as a standalone function?
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
This adds an experimental hook tentatively called useOptimisticState.
(The actual name needs some bikeshedding.)

The headline feature is that you can use it to implement optimistic
updates. If you set some optimistic state during a transition/action,
the state will be automatically reverted once the transition completes.

Another feature is that the optimistic updates will be continually
rebased on top of the latest state.

It's easiest to explain with examples; we'll publish documentation as
the API gets closer to stabilizing. See tests for now.

Technically the use cases for this hook are broader than just optimistic
updates; you could use it implement any sort of "pending" state, such as
the ones exposed by useTransition and useFormStatus. But we expect
people will most often reach for this hook to implement the optimistic
update pattern; simpler cases are covered by those other hooks.
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
…etermining if hook is stateful (facebook#27365)

facebook#26740 introduced regression:
React DevTools doesn't record updates for `useTransition` hook. I can
add more details about things on DevTools side, if needed.

The root cause is
https://github.com/facebook/react/blob/491aec5d6113ce5bae7c10966bc38a4a8fc091a8/packages/react-reconciler/src/ReactFiberHooks.js#L2728-L2730

React DevTools expects dispatch to be present for stateful hooks that
can schedule an update -
https://github.com/facebook/react/blob/2eed1328478e8c923fcb4e6abf5efbd9e1233402/packages/react-devtools-shared/src/backend/renderer.js#L1422-L1428

With these changes, we still call dispatch in `startTransition`, but
also patch `queue` object with it, so that React DevTools can recognise
`useTransition` as stateful hook that can schedule update.

I am not sure if this is the right approach to fix this, can we
distinguish if `startTransition` was called from `useTransition` hook or
as a standalone function?
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
This adds an experimental hook tentatively called useOptimisticState.
(The actual name needs some bikeshedding.)

The headline feature is that you can use it to implement optimistic
updates. If you set some optimistic state during a transition/action,
the state will be automatically reverted once the transition completes.

Another feature is that the optimistic updates will be continually
rebased on top of the latest state.

It's easiest to explain with examples; we'll publish documentation as
the API gets closer to stabilizing. See tests for now.

Technically the use cases for this hook are broader than just optimistic
updates; you could use it implement any sort of "pending" state, such as
the ones exposed by useTransition and useFormStatus. But we expect
people will most often reach for this hook to implement the optimistic
update pattern; simpler cases are covered by those other hooks.

DiffTrain build for commit 491aec5.
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.

6 participants