Closed discoverlance-com closed 1 week ago
Hi, thank you for this detailed request and the code snippet.
Since zsa-react-zod functions like useServerAction has access to the schema
Unfortunately useServerAction
actually does not have access to the schema from the action alone. This is because only async functions can be exported from the use server
files where the actions are stored. To get access to the schema on the client one can:
Option 1 in this case is better because you wouldn't want to wait for the schema to arrive to be able to show the client component.
From my understanding, react-hook-form
already does this on change validation with resolvers. I think if zsa-react
did have access to the schemas directly from actions -> it would make sense to include a function like this in the hook. However, since it doesn't have access to the schema, it pretty much turns into the exact same thing as react hook form resolvers where you need to pass your own schema.
If you find a way around this limitation, happy to review.
I see so it looks like it will not be possible ideally then... mostly given that the action and schema created is basically in a server action.
I think the best bet might be that given a createSeverAction
from zsa
, we can extract out the input object and then pass it into another custom hook like the useValidated
form above:
// action.ts
"use server"
import { createServerAction } from "zsa"
import { incrementSchema } from '@/lib/zod/schema'
import z from "zod"
export const incrementNumberAction = createServerAction()
.input(incrementSchema)
.handler(async ({ input }) => {
// Sleep for .5 seconds
await new Promise((resolve) => setTimeout(resolve, 500))
// Increment the input number by 1
return input.number + 1;
});
// lib/zod/schema.ts
import { z } from 'zod';
export const incrementSchema = z.object({
number: z.number()
});
// increment.tsx
const [data, err] = await incrementNumberAction({ number: 24 }); // or
const { isPending, execute, data, error, isError } = useServerAction(incrementNumberAction);
// and then for the client one
const { errors, setErrors, handleChange, hasErrors } = useValidatedForm(incrementSchema);
The problem now is that the errors can now be accessed from two different places even though it's the same zod schema so it will now be difficult to know which error to use or go for as you have two source of truths which is not the best and you will have to check the errors from two places.
But will this also not work the same way with the useServerAction
hook if we still put our zod schema in a different file and then, we can import it into our server action and also the useServerAction
hook and add that functionality? Or create another hook that does a similar thing to useServerAction
but allows you to pass in a zod schema to get client side error handling?
// action.tsx
"use server"
import { createServerAction } from "zsa"
import { incrementSchema } from '@/lib/zod/schema'
import z from "zod"
export const incrementNumberAction = createServerAction()
.input(incrementSchema)
.handler(async ({ input }) => {
// Sleep for .5 seconds
await new Promise((resolve) => setTimeout(resolve, 500))
// Increment the input number by 1
return input.number + 1;
});
// lib/zod/schema.ts
import { z } from 'zod';
export const incrementSchema = z.object({
number: z.number()
});
// increment.tsx
const { isPending, execute, data, error, isError, handleInputChange, handleFormChange }
= useServerAction(incrementNumberAction, incrementSchema);
// or another hook that accepts a schema as a second parameter and we keep useServerAction as is
const { isPending, execute, data, error, isError, handleInputChange, handleFormChange }
= useClientAction(incrementNumberAction, incrementSchema);
Maybe an optional second arg to useServerAction
and if that arg is passed in then it will return the extra schema hooks?
This is more of a feature request than an issue. I used a hook from the project, kirimase, useValidatedForm, please find this code below:
It basically receives a zod schema and returns errors and such utilities for interacting with the schema, but with this hook, I can basically add an
onChange={handleChange}
event to my form which then allows me to get errors as I type in the input. I think this will also be very useful for uses cases where the user is interested in such interactivity to handle errors on the fly as I also do whilst user types into the input.Since
zsa-react-zod
functions likeuseServerAction
has access to the schema, could it not also handle something like this and return ahandFormChange
and ahandleInputChange
function? In this case, thehandleFormChange
change could perform similar to this hook and validate each input on change and thehandeInputChange
could also be applied to individual input likehandleInputChange('name')
by accepting a field name or name input and return error only for that name input?Maybe this could also help with this issue: #124 as the user could get the input validated before even submitting so will not get that user experience of the form flicking to show the new errors. Of course this does not mean that the form will not be validated on the server as in my use case with the
useValidatedForm
hook I shared here, I also use the same zod schema in my server action to validate the schema once more but it takes the pain of having the user wait to submit the form before they get errors and it can also cherry pick each input field so user could type in an input and get errors for that input only without running the validation for the other inputs.Could this probably work best in the
useActionState
hook or perhaps a new hook altogether? I have only tried to usezsa-react
for a day so I have not been able to deep dive into the package to see if this is already possible but at least from the docs, I don't see such a feature for live updates of errors. I will take the time this week to also browse the codebase to see if I could suggest a solution but I am adding it here just in case anyone has ideas on it or it's already in the works/working. Thanks.