-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
[Flight] Progressively Enhanced Server Actions #26774
[Flight] Progressively Enhanced Server Actions #26774
Conversation
…ed before hydration
decodeAction lets you take a form that was posted back to the server and automatically decode the first action's server reference and its bound arguments. We must wait to fill up the FormData since we're going to pass them all as arguments to the action and we don't know how many there will be.
This uses an in-memory Server State that gets mutated and then the RSC payload is refreshed after a mutation takes place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
This automatically exposes `$$FORM_ACTIONS` on Server References coming from Flight. So that when they're used in a form action, we can encode the ID for the server reference as a hidden field or as part of the name of a button. If the Server Action is a bound function it can have complex data associated with it. In this case this additional data is encoded as additional form fields. To process a POST on the server there's now a `decodeAction` helper that can take one of these progressive posts from FormData and give you a function that is prebound with the correct closure and FormData so that you can just invoke it. I updated the fixture which now has a "Server State" that gets automatically refreshed. This also lets us visualize form fields. There's no "Action State" here for showing error messages that are not thrown, that's still up to user space. DiffTrain build for [aef7ce5](aef7ce5)
Includes the following upstream changes: - [aef7ce554](https://github.com/facebook/react/commits/aef7ce554) [Flight] Progressively Enhanced Server Actions ([vercel#26774](facebook/react#26774)) (Sebastian Markbåge) - [c10010a6a](https://github.com/facebook/react/commits/c10010a6a) [Fizz] Gracefully handle suspending in DOM configs ([vercel#26768](facebook/react#26768)) (Sebastian Markbåge) - [f533cee8c](https://github.com/facebook/react/commits/f533cee8c) Add useFormStatus to Flight fixture ([#26773](facebook/react#26773)) (Andrew Clark) - [2c1117a8d](https://github.com/facebook/react/commits/2c1117a8d) Reuse request so that a ReabableStream body does not become disturbed ([vercel#26771](facebook/react#26771)) (Andrew Gadzik) - [fa7a447b9](https://github.com/facebook/react/commits/fa7a447b9) [Fizz] Check for nullish values on ReactCustomFormAction ([vercel#26770](facebook/react#26770)) (Sebastian Markbåge)
Includes the following upstream changes: - [aef7ce554](https://github.com/facebook/react/commits/aef7ce554) [Flight] Progressively Enhanced Server Actions ([#26774](facebook/react#26774)) (Sebastian Markbåge) - [c10010a6a](https://github.com/facebook/react/commits/c10010a6a) [Fizz] Gracefully handle suspending in DOM configs ([#26768](facebook/react#26768)) (Sebastian Markbåge) - [f533cee8c](https://github.com/facebook/react/commits/f533cee8c) Add useFormStatus to Flight fixture ([#26773](facebook/react#26773)) (Andrew Clark) - [2c1117a8d](https://github.com/facebook/react/commits/2c1117a8d) Reuse request so that a ReabableStream body does not become disturbed ([#26771](facebook/react#26771)) (Andrew Gadzik) - [fa7a447b9](https://github.com/facebook/react/commits/fa7a447b9) [Fizz] Check for nullish values on ReactCustomFormAction ([#26770](facebook/react#26770)) (Sebastian Markbåge) <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation or adding/fixing Examples - The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md - Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # -->
Includes the following upstream changes: - [aef7ce554](https://github.com/facebook/react/commits/aef7ce554) [Flight] Progressively Enhanced Server Actions ([vercel#26774](facebook/react#26774)) (Sebastian Markbåge) - [c10010a6a](https://github.com/facebook/react/commits/c10010a6a) [Fizz] Gracefully handle suspending in DOM configs ([vercel#26768](facebook/react#26768)) (Sebastian Markbåge) - [f533cee8c](https://github.com/facebook/react/commits/f533cee8c) Add useFormStatus to Flight fixture ([#26773](facebook/react#26773)) (Andrew Clark) - [2c1117a8d](https://github.com/facebook/react/commits/2c1117a8d) Reuse request so that a ReabableStream body does not become disturbed ([vercel#26771](facebook/react#26771)) (Andrew Gadzik) - [fa7a447b9](https://github.com/facebook/react/commits/fa7a447b9) [Fizz] Check for nullish values on ReactCustomFormAction ([vercel#26770](facebook/react#26770)) (Sebastian Markbåge)
formAction={async () => { | ||
const result = await action(); | ||
console.log(result); | ||
}}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sebmarkbage It seems that progressively enhanced forms are only supported for voidy server actions. Or is that only a limitation of the Flight Fixture because closures with 'use server'
directives are not supported here, and if they were, we could define the action
/formAction
as before, and read the result?
EDIT: Hm, actually no, even if they were supported here, we still couldn't do anything with the result on the client, because the closure would run on the server. 🤦 Also, I now realise that progressively enhanced forms only make sense if the action is voidy, i.e. the mutation must result in some server-side state that can be rendered.
### What? When handling a server action, in the non-progressive enhanced case, React will attempt to parse the request body before verifying if a valid server action is received. This results in an "Error: Connection Closed" error being thrown, rather than ignoring the action and failing more gracefully ### Why? To support progressive enhancement with form actions, the `actionId` value is added as a hidden input in the form, so the action ID from the header shouldn't be verified until determining that we've reached the non-PE case. ([React ref](facebook/react#26774)). However, in #49187, support was added for a URL encoded form (which is not currently used, as indicated on the PR). Despite it not being used for server actions, it's currently possible to trigger this codepath, ie by calling redirect in an action handler with a 307/308 status code with some data in the URL. This would result in a 500 error. ### How? React should not attempt to parse the URL encoded form data until after we've verified the server action header for the non-PE case. x-ref NEXT-1733 [Slack context](https://vercel.slack.com/archives/C03S8ED1DKM/p1700674895218399?thread_ts=1700060786.749079&cid=C03S8ED1DKM)
This automatically exposes `$$FORM_ACTIONS` on Server References coming from Flight. So that when they're used in a form action, we can encode the ID for the server reference as a hidden field or as part of the name of a button. If the Server Action is a bound function it can have complex data associated with it. In this case this additional data is encoded as additional form fields. To process a POST on the server there's now a `decodeAction` helper that can take one of these progressive posts from FormData and give you a function that is prebound with the correct closure and FormData so that you can just invoke it. I updated the fixture which now has a "Server State" that gets automatically refreshed. This also lets us visualize form fields. There's no "Action State" here for showing error messages that are not thrown, that's still up to user space.
This automatically exposes `$$FORM_ACTIONS` on Server References coming from Flight. So that when they're used in a form action, we can encode the ID for the server reference as a hidden field or as part of the name of a button. If the Server Action is a bound function it can have complex data associated with it. In this case this additional data is encoded as additional form fields. To process a POST on the server there's now a `decodeAction` helper that can take one of these progressive posts from FormData and give you a function that is prebound with the correct closure and FormData so that you can just invoke it. I updated the fixture which now has a "Server State" that gets automatically refreshed. This also lets us visualize form fields. There's no "Action State" here for showing error messages that are not thrown, that's still up to user space. DiffTrain build for commit aef7ce5.
This automatically exposes
$$FORM_ACTION
on Server References coming from Flight. So that when they're used in a form action, we can encode the ID for the server reference as a hidden field or as part of the name of a button.If the Server Action is a bound function it can have complex data associated with it. In this case this additional data is encoded as additional form fields.
To process a POST on the server there's now a
decodeAction
helper that can take one of these progressive posts from FormData and give you a function that is prebound with the correct closure and FormData so that you can just invoke it.I updated the fixture which now has a "Server State" that gets automatically refreshed. This also lets us visualize form fields. There's no "Action State" here for showing error messages that are not thrown, that's still up to user space.