Closed nahtnam closed 3 weeks ago
Perhaps it would be fitting under zsa-react-hook-form
A very rudimentary idea of what I was thinking (without proper types or generics)
'use client';
import { useServerAction } from 'zsa-react';
import { useForm } from 'react-hook-form';
import { createServerAction, type inferServerActionInput } from 'zsa';
import { z } from 'zod';
const myAction = createServerAction()
.input(z.object({ num: z.number() }))
.handler(({ input }) => {
return input.num + 1;
});
type Input = inferServerActionInput<typeof myAction>;
export function useTest() {
const serverAction = useServerAction(myAction);
const { execute } = serverAction;
const form = useForm<Input>({});
async function handleSubmit(data: Input) {
const [_data, err] = await execute(data as any); // should be as FormDataLikeInput
if (!err) return;
if (err.code === 'INPUT_PARSE_ERROR') {
for (const fieldErrorKey of Object.keys(err.fieldErrors)) {
const fieldError =
err.fieldErrors[fieldErrorKey as keyof typeof err.fieldErrors];
for (const error of fieldError ?? []) {
form.setError(fieldErrorKey as any, { message: error });
}
}
const formErrors = err.formErrors;
if (formErrors.length) {
form.setError('root.formErrors', { message: formErrors });
}
return;
}
form.setError('root.serverError', {
...err,
});
}
return [serverAction, form, form.handleSubmit(handleSubmit)];
}
Hi, thank you for bringing this up. Good points.
Attaching #70 to this -- the most recent messages deal with RHF x ZSA.
Here is a helpful code snippet from that thread:
export function rhfErrorsFromZsa<T extends FieldValues = FieldValues>(
error: TZSAError<any> | null
): FieldErrors<T> | undefined {
if (!error) return
const {code: type, fieldErrors, formErrors, message} = error
return {
root: {type, message: message ?? formErrors?.[0]},
...Object.fromEntries(Object.entries(fieldErrors ?? {}).map(([name, errors]) => [name, {message: errors?.[0]}])),
} as FieldErrors<T>
}
then on the client you should be able to do something like this:
const { error, data, isPending, execute } = useServerAction(myAction)
const form = useForm<Data>({
mode: "onTouched",
resolver: zodResolver(zData),
errors: error ? rhfErrorsFromZsa(error) : undefined, // get rhf errors
defaultValues: data ?? defaultData,
})
However I understand that this is not ideal. Currently working on better error handling that should make this much smoother (see #102). Will ping here once its ready to go, should be soon! Thank you for posting these code snippets, will help me with my new PR + write docs to make it more clear. LMK if the above code doesn't work.
Hi, with zsa@0.3.4
you can now customize errors how you like them. Please check out these docs for an example with react hook form. Appreciate any feedback!
One thing I've been struggling with it all of the boilerplate code involved with setting up a form with server actions (not specific to this library)
One awesome idea that I think might work well would be if ZSA could automatically coerce the form errors and ZSA errors into react hook form errors.
What the integration would do is:
form.setError(field, errorMessage)
form.setError('root.serverError', errorMessage)
form.formState.isSubmitting
API wise, I'm not too sure what that would look like. Maybe something that looks like this: