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

[React 19] Submitting a <form> with an action will clear the input values #31649

Closed
debel27 opened this issue Nov 30, 2024 · 3 comments
Closed
Labels

Comments

@debel27
Copy link

debel27 commented Nov 30, 2024

Summary

I think a regression was introduced during the development of React 19 Canary.

Steps to reproduce

Render the following form and type something into the "query" input.

<form action={() => {}}>
  <input name="query" />
  <button type="submit">Search</button>
</form>
  • up until 19.0.0-canary-4c12339ce-20240408, submitting the form will preserve the input value
  • from 19.0.0-canary-adb717393-20240411 onwards, submitting the form will clear the input value

https://codesandbox.io/p/sandbox/elastic-merkle-yykcrc

Why I think this is a bug

Clearing inputs can be problematic if we keep displaying the form after submission.

A classical example is the display of validation errors after a rejected submit (by using the information returned by useActionState, for instance). If the inputs are cleared after submit, the errors would show up under empty inputs, which is not very helpful. Also, the user would have to fill in the complete form again, instead of simply fixing invalid values.

@debel27 debel27 changed the title [React 19] Submitting a from with an action will clear the input values [React 19] Submitting a <form> with an action will clear the input values Nov 30, 2024
@debel27
Copy link
Author

debel27 commented Nov 30, 2024

It appears the change was intentional:

This updates the behavior of form actions to automatically reset the
form's uncontrolled inputs after the action finishes.

This is a frequent feature request for people using actions and it
aligns the behavior of client-side form submissions more closely with
MPA form submissions.

@acdlite, given this design decision, do you have any recommendation on how to prevent this reset? For instance, we would want to keep the form state when the action gets rejected by the server, to let the user fix invalid values instead of filling in the whole form again.

I'm thinking about feeding the previous formData back into the form, like so:

function Form() {
  const [state, action] = useActionState(processForm, {
    status: "idle",
    formData: new FormData(),
  });

  return (
    <form action={action}>
      <input name="query" defaultValue={state.formData.get("query")} />
      <button type="submit">Search</button>
      {state.status === "success" && <div>Succesful query!</div>}
      {state.status === "error" && <div>{state.errorMessage}</div>}
    </form>
  );
}

async function processForm(prevState, formData) {
  const query = formData.get("query");
  if (query === "React") {
    return {
      status: "success",
      formData: new FormData(),
    };
  }
  return {
    status: "error",
    errorMessage: 'The query must be "React"',
    formData,
  };
}

Sandbox: https://codesandbox.io/p/sandbox/twilight-dream-fy3fzv

It seems like a good workaround, but in practice it will be more verbose to avoid TS errors.

@charles4221
Copy link

@debel27 I'm using a similar solution in my personal website I've recently rebuilt to use server actions etc.

When I want the form fields to stay populated with what was submitted (e.g. when my server action has found a validation error in the form data) I am returning the field data back to the form via the action's output:
https://github.com/charles4221/charlesharwood.dev/blob/main/src/app/contact/actions.ts#L45

Then I'm using those values as defaultValue exactly as your workaround is doing:
https://github.com/charles4221/charlesharwood.dev/blob/main/src/components/forms/ContactForm.tsx#L45

This is working great for me, and it allows me to easily decide which return paths from the form action should clear the inputs and which should not.

The other option would be to change your inputs to controlled inputs, which won't be cleared by the form action - but then you might end up holding a lot more client state that you don't really need and would need to be more explicit in clearing fields when you want to.

@eps1lon
Copy link
Collaborator

eps1lon commented Dec 2, 2024

This was an intentional change.

For discussions around opting out of this behavior, check out #29034

@eps1lon eps1lon closed this as not planned Won't fix, can't repro, duplicate, stale Dec 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants