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

Add client side validation #1

Open
kirill-konshin opened this issue Dec 22, 2024 · 4 comments
Open

Add client side validation #1

kirill-konshin opened this issue Dec 22, 2024 · 4 comments

Comments

@kirill-konshin
Copy link

kirill-konshin commented Dec 22, 2024

I was writing an article on React 19 forms and Zod, and before submission I decided to do one more round of googling, if something similar already exists... and found your wonderful article.

Fun thing is that I ended up with almost exactly the same implementation as you, almost line by line the same where it matters.

So I'd like to share how I implemented client side validation, it's just a few more lines of code to what you already have.

If you extract validation from server action into a validation function, you can call it on client side as well, before calling server action ;)

function validate(formData) {
  const formDataObj = Object.fromEntries(formData);
  const { data, error } = addItemSchema.safeParse(formDataObj);
  if (error) {
    return { formData, errors: error.flatten().fieldErrors };
  }
  return { formData, data };
}

Just make sure it's not in actions file, as it's marked as "use server";, probably types.ts is the right place for it.

So your action becomes:

export async function addItemAction(
  _: AddItemState,
  formData: FormData,
): Promise<AddItemState> {
  const res = validate(formData);
  if (res.error) return res;
  addItem(res.data);
  revalidatePath("/");
  return {};
}

and on client side:

const [state, formAction] = useActionState<AddItemState, FormData>(
    async (prev, formData) => {
       const res = validate(formData);
       if (res.error) return res;
       return addItemAction(prev, formData);
    },
    {},
  );

This way you save a roundtrip to server and apply exactly the same validation in both realms.

@carderne
Copy link
Owner

Hey @kirill-konshin glad you enjoyed the post and interesting you hit the exact same solution. :)

Thanks for sharing this, leaving out client-side validation was a bit of an omission.
I was trying to get as close as possible to a "backend-only" approach... but this is super neat!
Mind if I add it to the blog (with credit) and repo?

@kirill-konshin
Copy link
Author

Of course! Collaboration is what moves industry forward.

@carderne
Copy link
Owner

Added: https://rdrn.me/react-forms/#client-validation

And added to the repo as well: 71ba020

Having to return { errors: {} } isn't ideal, but I couldn't come up with a more elegant way of doing the types... You could return res, but that just seems more confusing (and unnecessary data).

@kirill-konshin
Copy link
Author

Thanks for the mention!

Having to return { errors: {} } isn't ideal, but I couldn't come up with a more elegant way of doing the types... You could return res, but that just seems more confusing (and unnecessary data).

Res is basically server returning what it received, along with errors, can be useful sometimes. Since solution is zod-centric its error structure as return seems to be OK. Besides, people who work with zod are well aware of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants