You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7dd9e90
Browse filesBrowse the repository at this point in the historyBrowse files
When the form is submitted, React calls `addProductToCart(formData)`, which calls `addToCart(productId, formData)`.
217
217
218
-
[`useActionState`](/reference/react/useActionState) passes the previous state before `FormData`. Bound arguments come first, so the Server Function receives the bound values, the previous state, and then `formData`. Define that function in a separate file and bind it from the Client Component.
218
+
If you also use [`useActionState`](/reference/react/useActionState), the Server Function receives `productId`, `previousState`, and `formData`, in that order. Define that function in a separate file and bind it from the Client Component.
219
219
220
220
#### A function in the component {/*passing-extra-data-function*/}
221
221
@@ -248,15 +248,15 @@ export async function updateCart(productId, formData) {
248
248
}
249
249
```
250
250
251
-
Users can submit this form only after JavaScript loads.
251
+
Because `addToCart` runs in the browser, the component's JavaScript must load before the form can submit.
252
252
253
253
</DeepDive>
254
254
255
255
---
256
256
257
257
### Displaying a pending state during form submission {/*display-a-pending-state-during-form-submission*/}
258
258
259
-
To display a pending state when a form is being submitted, you can call the `useFormStatus` Hook in a component rendered in a `<form>` and read the `pending` property returned.
259
+
To display a pending state when a form is being submitted, you can call the [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) Hook in a component rendered in a `<form>` and read the `pending` property returned.
260
260
261
261
Here, we use the `pending` property to indicate the form is submitting.
262
262
@@ -302,14 +302,14 @@ To learn more about the `useFormStatus` Hook, see the [reference documentation](
302
302
303
303
### Optimistically updating form data {/*optimistically-updating-form-data*/}
304
304
305
-
The `useOptimistic` Hook provides a way to optimistically update the user interface before a background operation, like a network request, completes. In the context of forms, this technique helps to make apps feel more responsive. When a user submits a form, instead of waiting for the server's response to reflect the changes, the interface is immediately updated with the expected outcome.
305
+
The [`useOptimistic`](/reference/react/useOptimistic) Hook provides a way to optimistically update the user interface before a background operation, like a network request, completes. In the context of forms, this technique helps to make apps feel more responsive. When a user submits a form, instead of waiting for the server's response to reflect the changes, the interface is immediately updated with the expected outcome.
306
306
307
307
For example, when a user types a message into the form and hits the "Send" button, the `useOptimistic` Hook allows the message to immediately appear in the list with a "Sending..." label, even before the message is actually sent to a server. This "optimistic" approach gives the impression of speed and responsiveness. The form then attempts to truly send the message in the background. Once the server confirms the message has been received, the "Sending..." label is removed.
@@ -374,7 +376,7 @@ To learn more about the `useOptimistic` Hook, see the [reference documentation](
374
376
375
377
### Handling form submission errors {/*handling-form-submission-errors*/}
376
378
377
-
To handle errors thrown by a function passed to a `<form>`'s `action` prop, wrap the form in an Error Boundary. React displays the boundary's fallback when the function throws.
379
+
To handle errors thrown by a function passed to a `<form>`'s `action` prop, wrap the form in an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary). React displays the boundary's fallback when the function throws.
378
380
379
381
<Sandpack>
380
382
@@ -412,15 +414,13 @@ export default function Search() {
412
414
413
415
</Sandpack>
414
416
415
-
---
416
-
417
-
### Displaying a form submission error without JavaScript {/*display-a-form-submission-error-without-javascript*/}
417
+
#### Handling form submission errors before JavaScript loads {/*display-a-form-submission-error-without-javascript*/}
418
418
419
419
Displaying a form submission error message before the JavaScript bundle loads for progressive enhancement requires that:
420
420
421
421
1.`<form>` be rendered by a [Client Component](/reference/rsc/use-client)
422
422
1. the function passed to the `<form>`'s `action` prop be a [Server Function](/reference/rsc/server-functions)
423
-
1. the `useActionState` Hook be used to display the error message
423
+
1. the [`useActionState`](/reference/react/useActionState) Hook be used to display the error message
424
424
425
425
Define the Server Function in a separate file with the [`'use server'`](/reference/rsc/use-server) directive. It receives the previous state followed by the submitted `FormData`:
426
426
@@ -469,75 +469,56 @@ If the form is submitted before JavaScript loads, React includes the Server Func
469
469
470
470
### Preserving form values after an Action {/*preserve-form-values-after-an-action*/}
471
471
472
-
When you pass a function to `action` or `formAction`, React resets the form's [uncontrolled fields](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form) after the Action succeeds. To keep the submitted values, store each value in state and pass it to that field's `defaultValue`. The reset then restores each field to its `defaultValue` instead of clearing it.
473
-
474
-
To keep those values when users submit the form before JavaScript loads, render the `<form>` from a [Client Component](/reference/rsc/use-client) and pass a [Server Function](/reference/rsc/server-functions) to [`useActionState`](/reference/react/useActionState). Pass the Action it returns to the form's `action` prop. The Server Function receives the previous state, followed by the submitted `FormData`, as shown in [Displaying a form submission error without JavaScript](#display-a-form-submission-error-without-javascript). Return an object with the values to keep, and pass each value, such as `state.title`, to the matching field's `defaultValue`:
When a function passed to `action` or `formAction` completes without throwing, React resets the form's [uncontrolled fields](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form). You may want to keep the submitted values after saving edits, or when the Action returns a [validation error](/reference/react/useActionState#displaying-validation-errors-and-preserving-form-values).
488
473
489
-
```js
490
-
// EditForm.js
491
-
'use client';
474
+
To preserve those values, you can store them with [`useState`](/reference/react/useState) and pass them to each field's [`defaultValue`](/reference/react-dom/components/input#providing-an-initial-value-for-an-input). Update the state when the Action finishes. React applies the updated defaults before resetting the form, so the fields keep those values.
Users can submit the form before JavaScript loads. After the Action succeeds, `defaultValue={state.title}` restores the title from the returned object.
513
-
514
-
For a form that submits only after JavaScript loads, store the values with [`useState`](/reference/react/useState). Update that state when the Action finishes. React applies the new `defaultValue`, then resets the form, so each field shows the submitted value:
476
+
Try changing the title and clicking **Save**. In this example, [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) shows "Saving..." during a simulated one-second request. Then `setTitle` updates the saved title and preserves it in the input.
515
477
516
478
<Sandpack>
517
479
518
480
```js src/App.js
519
-
import { useState } from'react';
481
+
import { startTransition, useState } from'react';
482
+
importSaveButtonfrom'./SaveButton.js';
520
483
521
484
exportdefaultfunctionEditForm() {
522
485
const [title, setTitle] =useState('My draft');
523
486
524
487
asyncfunctionsaveAction(formData) {
525
488
awaitnewPromise((res) =>setTimeout(res, 1000));
526
-
setTitle(formData.get('title'));
489
+
startTransition(() => {
490
+
setTitle(formData.get('title'));
491
+
});
527
492
}
528
493
529
494
return (
530
495
<form action={saveAction}>
531
496
<input name="title" defaultValue={title} />
532
-
<button type="submit">Save</button>
497
+
<SaveButton />
498
+
<p>Saved title: {title}</p>
533
499
</form>
534
500
);
535
501
}
536
502
```
537
503
504
+
```js src/SaveButton.js hidden
505
+
import { useFormStatus } from'react-dom';
506
+
507
+
exportdefaultfunctionSaveButton() {
508
+
const { pending } =useFormStatus();
509
+
return (
510
+
<button type="submit" disabled={pending}>
511
+
{pending ?'Saving...':'Save'}
512
+
</button>
513
+
);
514
+
}
515
+
```
516
+
538
517
</Sandpack>
539
518
540
-
Call a Server Function from `saveAction`, then store its return value in state. Because `saveAction` is defined in the Client Component, users can submit this form only after JavaScript loads:
519
+
The call to `setTitle`[after `await`](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition) needs another [`startTransition`](/reference/react/startTransition) to mark it as a Transition update.
520
+
521
+
`saveAction` can also call a [Server Function](/reference/rsc/server-functions) and store its return value:
541
522
542
523
```js
543
524
// actions.js
@@ -552,25 +533,58 @@ export async function submitTitle(formData) {
552
533
}
553
534
```
554
535
536
+
Add [`'use client'`](/reference/rsc/use-client) at the top of the component's file, import `submitTitle`, and replace `saveAction`. The rest of the form stays the same:
537
+
538
+
```js
539
+
import { submitTitle } from'./actions.js';
540
+
541
+
asyncfunctionsaveAction(formData) {
542
+
constsavedTitle=awaitsubmitTitle(formData);
543
+
startTransition(() => {
544
+
setTitle(savedTitle);
545
+
});
546
+
}
547
+
```
548
+
549
+
#### Preserving form values before JavaScript loads {/*preserving-form-values-before-javascript-loads*/}
550
+
551
+
With [`useActionState`](/reference/react/useActionState), React can display a [Server Function](/reference/rsc/server-functions)'s returned value before hydration completes. The form can use those values as its new defaults. In a [Client Component](/reference/rsc/use-client), `useActionState` receives the Server Function and returns an Action for the form's `action` prop.
552
+
553
+
See [Handling form submission errors before JavaScript loads](#display-a-form-submission-error-without-javascript) for the same behavior with errors.
554
+
555
+
The Server Function receives the previous state followed by the submitted `FormData`. In this example, `updateTitle` saves the title and returns `{ title }`, which becomes the new state. Passing `state.title` to `defaultValue` preserves the saved title after the reset:
@@ -584,7 +598,7 @@ The examples above keep every submitted value by storing it before the reset. Yo
584
598
585
599
***Keep values only when validation fails.** Return the same state shape from every submission. When validation fails, include the submitted `FormData` and read each field with `state.submitted?.get('title') ?? ''`. When validation succeeds, set that `FormData` to `null` so the reset clears those fields. [`useActionState`](/reference/react/useActionState#displaying-validation-errors-and-preserving-form-values) shows this pattern.
586
600
587
-
***Skip the reset with `onSubmit`.** Handle the submission in `onSubmit`, call `e.preventDefault()`, and run the Action inside [`startTransition`](/reference/react/useTransition). Because the form's `action` does not run, React does not reset the form. Users can submit this form only after JavaScript loads.
601
+
***Skip the reset with `onSubmit`.** Handle the submission in `onSubmit`, call `e.preventDefault()`, and run the Action inside [`startTransition`](/reference/react/useTransition). Because the form's `action` does not run, React does not reset the form.
588
602
589
603
***Reset at a specific moment.** Call the form element's [`reset()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset) method to immediately reset uncontrolled fields to their default values. To schedule a reset as part of an Action or Transition, call [`requestFormReset`](/blog/2024/12/05/react-19#form-actions) from `react-dom` instead.
590
604
@@ -596,7 +610,7 @@ The examples above keep every submitted value by storing it before the reset. Yo
A form can have more than one submit button, each running a different Action. A button without `formAction` runs the form's `action`; a button with `formAction` runs its own Action instead. For example, the form below publishes an article by default, but its **Save draft** button stores the current content without publishing it:
613
+
A form can have more than one submit button, each running a different Action. A button without `formAction` runs the form's `action`; a button with `formAction` runs its own Action instead. For example, the form below publishes an article by default, but its **Save draft** button stores the current content without publishing it. It uses [`useActionState`](/reference/react/useActionState) to preserve the saved draft:
600
614
601
615
<Sandpack>
602
616
@@ -650,3 +664,13 @@ export default function ArticleForm() {
650
664
```
651
665
652
666
</Sandpack>
667
+
668
+
---
669
+
670
+
## Troubleshooting {/*troubleshooting*/}
671
+
672
+
### My form fields are cleared after submission {/*my-form-fields-are-cleared-after-submission*/}
673
+
674
+
When a function passed to `action` or `formAction` succeeds, React resets the form's uncontrolled fields to their default values. Text fields without a `defaultValue` become empty. Returning a validation error instead of throwing also triggers this reset.
675
+
676
+
To keep a submitted value, store it in state and pass it to the field's `defaultValue`. See [Preserving form values after an Action](#preserve-form-values-after-an-action) for examples, or [preserving values when validation fails](/reference/react/useActionState#displaying-validation-errors-and-preserving-form-values).
Copy file name to clipboardExpand all lines: src/content/reference/react/useActionState.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1245,7 +1245,7 @@ When validation fails, `updateName` returns an error and the submitted `FormData
1245
1245
1246
1246
<RSC>
1247
1247
1248
-
When the `reducerAction` passed to `useActionState` is a [Server Function](/reference/rsc/server-functions), pass the returned `submitAction` to the form's `action` prop. React can then display the Server Function's returned value before hydration completes. Return the submitted `FormData` and use it to set each field's `defaultValue` to preserve those values before JavaScript loads. On pages with dynamic content, you can also use the optional `permalink` parameter for progressive enhancement.
1248
+
The example above runs `updateName` in the browser. To display the error and preserve the submitted name before JavaScript loads, make `updateName`a [Server Function](/reference/rsc/server-functions). Keep passing `submitAction` to the form's `action` prop. React can then display the Server Function's returned value before hydration completes. See [preserving form values before JavaScript loads](/reference/react-dom/components/form#preserving-form-values-before-javascript-loads) for the setup. On pages with dynamic content, you can also use the optional [`permalink`](#parameters) parameter for progressive enhancement.
0 commit comments