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_useFormStatus #26722

Merged
merged 4 commits into from
Apr 26, 2023
Merged

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Apr 25, 2023

This hook reads the status of its ancestor form component, if it exists.

const {pending, data, action, method} = useFormStatus();

It can be used to implement a loading indicator, for example. You can think of it as a shortcut for implementing a loading state with the useTransition hook.

For now, it's only available in the experimental channel. We'll share docs once its closer to being stable. There are additional APIs that will ship alongside it.

Internally it's implemented using startTransition + a context object. That's a good way to think about its behavior, but the actual implementation details may change in the future.

Because form elements cannot be nested, the implementation in the reconciler does not bother to keep track of multiple nested "transition providers". So although it's implemented using generic Fiber config methods, it does currently make some assumptions based on React DOM's requirements.

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

react-sizebot commented Apr 25, 2023

Comparing: 6eadbe0...1279935

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 = 164.02 kB 164.02 kB = 51.71 kB 51.71 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.35% 169.73 kB 170.32 kB +0.40% 53.41 kB 53.62 kB
facebook-www/ReactDOM-prod.classic.js = 566.81 kB 566.81 kB = 100.13 kB 100.13 kB
facebook-www/ReactDOM-prod.modern.js = 550.54 kB 550.55 kB +0.01% 97.32 kB 97.33 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 +0.57% 808.77 kB 813.37 kB +0.68% 176.04 kB 177.25 kB
oss-experimental/react-art/cjs/react-art.production.min.js +0.53% 96.68 kB 97.20 kB +0.57% 29.71 kB 29.88 kB
oss-experimental/react-art/umd/react-art.development.js +0.52% 923.99 kB 928.79 kB +0.61% 195.07 kB 196.26 kB
oss-experimental/react-reconciler/cjs/react-reconciler.development.js +0.49% 909.66 kB 914.08 kB +0.60% 194.51 kB 195.67 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.min.js +0.45% 113.90 kB 114.42 kB +0.50% 34.85 kB 35.02 kB
oss-experimental/react-dom/cjs/react-dom.development.js +0.43% 1,291.02 kB 1,296.55 kB +0.56% 285.17 kB 286.76 kB
oss-experimental/react-dom/umd/react-dom.development.js +0.43% 1,353.57 kB 1,359.35 kB +0.55% 288.03 kB 289.62 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.development.js +0.42% 1,309.07 kB 1,314.61 kB +0.54% 289.51 kB 291.07 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.min.js +0.42% 122.91 kB 123.43 kB +0.42% 37.05 kB 37.20 kB
oss-experimental/react-art/umd/react-art.production.min.js +0.38% 133.94 kB 134.46 kB +0.25% 41.95 kB 42.06 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.35% 169.73 kB 170.32 kB +0.40% 53.41 kB 53.62 kB
oss-experimental/react-dom/umd/react-dom.production.min.js +0.35% 169.57 kB 170.16 kB +0.31% 53.76 kB 53.93 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.min.js +0.34% 175.94 kB 176.53 kB +0.42% 55.73 kB 55.96 kB
oss-experimental/react-server/cjs/react-server.production.min.js +0.34% 25.01 kB 25.10 kB +0.28% 8.55 kB 8.57 kB
oss-experimental/react-dom/umd/react-dom.profiling.min.js +0.33% 178.55 kB 179.14 kB +0.35% 56.09 kB 56.28 kB
oss-experimental/react-dom/cjs/react-dom.profiling.min.js +0.33% 179.36 kB 179.95 kB +0.31% 55.87 kB 56.04 kB

Generated by 🚫 dangerJS against 1279935

The DOM fiber config will import stuff from this module, so I think it
makes sense for it to live in the bindings package, alongside the
fiber config.
The useTransition hook is a thin wrapper around useState; all it really
does it map over the return value. We going to change the return value
for form actions, anyway, so we should call useState directly instead.
@acdlite acdlite force-pushed the useFormStatus branch 3 times, most recently from 9b56dc2 to 265aa9c Compare April 26, 2023 02:52
@acdlite acdlite changed the title [WIP] experimental_useFormStatus Implement experimental_useFormStatus Apr 26, 2023
@acdlite acdlite marked this pull request as ready for review April 26, 2023 03:10
@acdlite
Copy link
Collaborator Author

acdlite commented Apr 26, 2023

@sebmarkbage This is ready for review now except for the Flow error (which I don't yet understand)

@acdlite acdlite force-pushed the useFormStatus branch 2 times, most recently from 889fc3f to 721b14b Compare April 26, 2023 03:41
@acdlite acdlite force-pushed the useFormStatus branch 3 times, most recently from 6eda637 to 5caaa53 Compare April 26, 2023 04:16
Updates the internals of async form actions so they can use a custom
pending state type, instead of a boolean. I'm not sure this is how we'll
end up doing it once optimistic state is implemented, but it fits with
how we handle the isPending state of useTransition.

The next step is to connect this to useFormStatus, which will read
the value of the nearest pending form state using context.
@acdlite acdlite force-pushed the useFormStatus branch 5 times, most recently from cffd0c5 to eb76e33 Compare April 26, 2023 14:53
This hook reads the status of its ancestor form component, if it exists.

  const {pending, data, action, method} = useFormStatus();

It can be used to implement a loading indicator, for example. You can
think of it as a shortcut for implementing a loading state with the
useTransition hook.

For now, it's only available in the experimental channel. We'll share
docs once its closer to being stable. There are additional APIs that
will ship alongside it.

Internally it's implemented using startTransition + a context object.
That's a good way to think about its behavior, but the actual
implementation details may change in the future.

Because form elements cannot be nested, the implementation in the
reconciler does not bother to keep track of multiple nested "transition
providers". So although it's implemented using generic Fiber config
methods, it does currently make some assumptions based on React
DOM's requirements.
@debel27
Copy link

debel27 commented Apr 26, 2023

Is this a general-purpose hook?

I often have the situation where the submit <button> is located outside the <form> element.

<form id="form-id">
  {/* ... */}
</form>

<button type="submit" form="form-id">
  Submit
</button>

Ideally, I'd like to display a loading indicator inside the button when the form is submitting. It does not seem feasible with the current version of useFormStatus. Is it out of scope?

@acdlite
Copy link
Collaborator Author

acdlite commented Apr 26, 2023

#26722 (comment)

Ideally, I'd like to display a loading indicator inside the button when the form is submitting. It does not seem feasible with the current version of useFormStatus. Is it out of scope?

That's a feature we've discussed adding (like by passing the id of the form as an argument to the hook) but it won't be in the initial version. But in the meantime there will be lower level APIs that you can use to implement a loading state yourself. (The same ones you'd use for anything more advanced that what useFormStatus provides out of the box.)

@acdlite acdlite merged commit 540bab0 into facebook:main Apr 26, 2023
2 checks passed
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)

---------
@nihgwu
Copy link
Contributor

nihgwu commented Oct 22, 2023

But in the meantime there will be lower level APIs that you can use to implement a loading state yourself. (The same ones you'd use for anything more advanced that what useFormStatus provides out of the box.)

@acdlite can you elaborate, is there quick ways without top level context?

That's a feature we've discussed adding

When can we expect it be available, IMO the current implementation is incomplete, as in practice submit button outside of form while connected with id is the only way in some cases

EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
This hook reads the status of its ancestor form component, if it exists.

```js
const {pending, data, action, method} = useFormStatus();
```

It can be used to implement a loading indicator, for example. You can
think of it as a shortcut for implementing a loading state with the
useTransition hook.

For now, it's only available in the experimental channel. We'll share
docs once its closer to being stable. There are additional APIs that
will ship alongside it.

Internally it's implemented using startTransition + a context object.
That's a good way to think about its behavior, but the actual
implementation details may change in the future.

Because form elements cannot be nested, the implementation in the
reconciler does not bother to keep track of multiple nested "transition
providers". So although it's implemented using generic Fiber config
methods, it does currently make some assumptions based on React DOM's
requirements.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
This hook reads the status of its ancestor form component, if it exists.

```js
const {pending, data, action, method} = useFormStatus();
```

It can be used to implement a loading indicator, for example. You can
think of it as a shortcut for implementing a loading state with the
useTransition hook.

For now, it's only available in the experimental channel. We'll share
docs once its closer to being stable. There are additional APIs that
will ship alongside it.

Internally it's implemented using startTransition + a context object.
That's a good way to think about its behavior, but the actual
implementation details may change in the future.

Because form elements cannot be nested, the implementation in the
reconciler does not bother to keep track of multiple nested "transition
providers". So although it's implemented using generic Fiber config
methods, it does currently make some assumptions based on React DOM's
requirements.

DiffTrain build for commit 540bab0.
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.

None yet

6 participants