Skip to content

Docs: useFormState and sensitive data #63141

@nagman

Description

@nagman

What is the improvement or update you wish to see?

I would like to see an example on how to use useFormState along with sensitive data that must not be exposed on the client.

I've tried several solutions, and the only one that worked was defining the action in a closure in the parent server component, then pass the action to the child client component that uses useFormState:

// parent
async function ServerContactForm({recipients}: {recipients: string[]}) {
  async function handleSubmit(prevState: any, formData: FormData) {
    'use server';
    return submitContactForm(recipients, formData);
  }

  return (
    <ClientContactForm action={handleSubmit} />
  );
}

// child
'use client';

function ClientContactForm({action}: {
    action: (
      prevState: any,
      formData: FormData,
    ) => ReturnType<typeof submitContactForm>;
  }) {
  const [state, formAction] = useFormState(action, {});

  return (
    <form action={formAction}>
    // ...
    </form>
  );
}

The solution with .bind() in the parent component doesn't work as it exposes sensitive data in a <input type="hidden" />.
Neither does the solution where I pass the sensitive data to the client component.

We lack explanations on how it internally works because the behavior is quite unpredictable and I had to test several cases before finding one that does the job (and I hope it really hides my sensitive data because I can't know how it's processed under the hood).

It would be nice to have a real case example in the docs having:

  • a contact form
  • some sensitive data passed to the action
  • a loading state (this is really annoying to create children components just to call useFormStatus when all you want is just a simple CSS feedback on your form - can't the status be included in the useFormState hook?)
  • a feedback returned by the action and displayed along the contact form

That is, one must say, the most common use case for form actions.
Yet I struggle with it for hours.

Is there any context that might help us understand?

The docs explain how to use useFormState and how to pass actions into closures in order to hide sensitive data, but not how to use both together.

Does the docs page already exist? Please link to it.

https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#server-side-validation-and-error-handling

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions