idopesok / zsa Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://zsa.vercel.app
License: MIT License
Home Page: https://zsa.vercel.app
License: MIT License
Hello!
I've been working on my own trpc like server action library then came across this, it's basically the exact api I had, so thinking I might as well use this.
The only thing im missing from this library is the ability to return formatted validation errors that comes from zod i.e. result.error.flatten().fieldErrors
when safeParse fails.
Looking at your code I see that you just throw a custom Error when this fails but the response to the client is stringified json, I guess I could parse it on the frontend but my ideal api would be something like this:
export function LoginForm() {
const { execute, data, error } = useServerAction(login)
return (
<form action={execute} className="space-y-2">
<FormField
required
minLength={3}
label="Email address"
name="email"
errors={error?.fieldErrors?.email}
/>
<FormField
required
minLength={8}
label="Password"
name="password"
type="password"
errors={error?.fieldErrors?.password}
placeholder="********"
/>
<FormError error={error.formError} />
<FormButton className="w-full">Login</FormButton>
</form>
)
Wondering if you've run into similar needs or if theres another way of achieving something similar this? trpc has the formatError function which allows you to customise the error response so I could add fieldErrors as a custom key, and formError for general errors. What do you think?
Thanks for the good work!
We need to add tests for what happens when a redirect is called with useServerAction
. It should still show isPending
up until the transition ends, and the callbacks should be called after the transition ends.
It would be convenient to add a helper chaining method (e.g. .throw()
) so that the server action would throw the error instead of returning it.
Use cases: the error.tsx
and <ErrorBoundary />
components would automatically work if the server action throws the error, now I have to manually re-throw it
// page.tsx
const [data, err] = await action()
if (err) {
throw new Error(err)
}
if with the chaining method I could just do
const action2 = action.throw()
const data = await action2()
This worked before I upgraded today. Might be related to #91 ?
"zsa": "^0.3.2",
"zsa-react": "^0.1.4"
// Server action
revalidatePath(`/admin/shop/categories/${categoryId}`)
return {
message: 'Item added',
}
const onClick = async () => {
console.debug('Fired')
const [, err] = await execute({
catalogItemId: Number(item.objectID),
categoryId,
})
console.debug('This works if err')
console.debug('err', err)
if (err) {
toast({
title: 'Error',
description: 'Error adding item',
})
return
}
console.log('Never called if revalidatePath is hit')
toast({
title: 'Item added โ
',
description: 'Item added!',
})
}
fuzzy vision:
const router = createRouter()
router.get("/posts", getPostAction)
router.post("/posts/{postId}/replies", createReplyAction)
export { GET, POST } = createRouteHandlers(router)
It should also generate the OpenAPI document
Is there any way to use zsa-react-query with prefetchQuery and useSuspenseQuery?
It would be nice to be able to prefetch data with validation, type safety and also to stay with react-query ecosystem
Hi @IdoPesok,
I'm throwing a ZSAError
within a serverAction.
if (!organization) {
throw new ZSAError('NOT_FOUND', 'Organization not found');
}
Can we customise the error payload please? I would like to exclude the stack trace and only return message
and code
. Seems a bit redundant to have both data
and message
with the same value.
{
"data": "Organization not found",
"name": "Error",
"stack": "\"Error: Organization not found\\n at $$ACTION_0 (webpack-internal:///(rsc)/./src/lib/actions/organizations/actions.ts:35:15)\\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\\n at async wrapper (webpack-internal:///(rsc)/../../node_modules/.pnpm/[email protected]/node_modules/zsa/dist/index.mjs:393:22)\\n at async getResponseFromAction (webpack-internal:///(rsc)/../../node_modules/.pnpm/[email protected]/node_modules/zsa-openapi/dist/index.mjs:2043:25)\\n at async handler (webpack-internal:///(rsc)/../../node_modules/.pnpm/[email protected]/node_modules/zsa-openapi/dist/index.mjs:2149:12)\\n",
"message": "Organization not found",
"code": "NOT_FOUND"
}
Ideally I would like to have:
{
"code": "NOT_FOUND",
"message": "Organization not found"
}
or for a validation error:
{
"code": "INPUT_PARSE_ERROR",
"message": "Invalid uuid",
"formattedErrors": { ... }
}
What do you think?
I'm not sure if this was intended, but if the handler throws a normal Error, it seems like the error message is replaced with {}. It would be nice if normal exceptions would be wrapped and sent back to the UI as expected.
export const createGroupAction = authenticatedAction
.createServerAction()
.input(schema)
.handler(async ({ input: { name, description }, ctx: { user } }) => {
throw new Error("GG");
});
notice how the "GG" shows up nowhere in the ZSAError. I'd personally expect GG to show up in the message property or at least data property
Hi, thanks for this library, looks cool!
For useServerAction
, would you consider replicating the API of React's useActionState
hook to make it easier to migrate / understand?
Hi,
When using redirect function in a server action made using ZSA library, it catches the error thrown internally in redirect and returns an error even if the server action was successful. I even tried moving the redirect function call to onSuccess callback but I got the same result.
Reference -> https://nextjs.org/docs/app/building-your-application/routing/redirecting
I am loving the library so far ๐ฅ
One issue im having is when passing formdata from client side execute hook.
Here's how the hook looks like in the client:
/** @actions */
const { execute, isPending } =
useServerAction(createAction, {
});
My Submit Handler
const handleSubmit = (values) => {
const formData = new FormData();
formData.append('Name', "Hello");
execute(formData);
};
export const createAction = createServerAction()
.input(typedAnySchema(), { type: 'formData' })
.handler(async ({ input }) => {
console.log(input, input instanceof FormData);
});
I don't know why the instance of input comes false here, it should be true ?
https://trpc.io/docs/client/react/useUtils
One of my favorite things about tRPC is that it automatically handles your query keys in a typesafe way:
const utils = trpc.useUtils();
utils.post.all.refetch();
This way you don't have to juggle keys manually.
It looks like that zsa
has a few utilities to make query keys more typesafe, but it's still a lot of boilerplate that you have to constantly synchronize:
export const QueryKeyFactory = createServerActionsKeyFactory({
getPosts: () => ["getPosts"],
getFriends: () => ["getFriends"],
getPostsAndFriends: () => ["getPosts", "getFriends"],
somethingElse: (id: string) => ["somethingElse", id],
getRandomNumber: () => ["getRandomNumber"],
})
So it would be nice if zsa
can provide an equivalent to tRPC's useUtils
that would absolve the need for all of this manual work.
I want to do i.e.
createServerAction()
.input(...)
.onSuccess(() => redirect("my/onsuccess/url")
.handler(() => ...);
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:
const [form, ...otherStuff] = useReactServerActionHookForm(action, additionalReactHookFormProps)
Hi. I'm was working on a project using older versions and I moved to latest to have new ZSAError and the code that's working in older versions now leaves my UI loading
- "zsa": "^0.2.3",
- "zsa-react": "^0.1.3"
+ "zsa": "^0.3.3",
+ "zsa-react": "^0.1.4"
This is my action
async function checkUsername(username: string, user: SafeUser) {
const foundUsers = await db
.select({ id: users.id })
.from(users)
.where(and(eq(users.username, username), ne(users.id, user.id)))
.limit(1)
return foundUsers.length > 0
}
const input = z.object({
name: z.string().min(3),
username: z
.string()
.min(3, { message: 'Username must be at least 3 characters long.' })
.max(20, { message: 'Username cannot be longer than 20 characters.' })
.regex(/^[a-zA-Z0-9_\-.]*$/, {
message:
'Invalid characters in username. Only leters, numbers and "-" without spaces. No accents.',
}),
})
type Input = z.infer<typeof input>
async function validateUniqueUsername({
data,
user,
}: {
data: Input
user: SafeUser
}) {
const asyncInput = input.extend({
username: input.shape.username.refine(async (username) => {
return checkUsername(username, user)
}, { message: 'Username is already taken.' }),
})
const uniqueError = await asyncInput.safeParseAsync(data)
console.log("uniqueError", uniqueError)
if (uniqueError.success) return
const flattenedErrors = uniqueError.error.flatten()
const formattedErrors = uniqueError.error.format()
throw new ZSAError('INPUT_PARSE_ERROR', uniqueError.error, {
inputParseErrors: {
fieldErrors: flattenedErrors?.fieldErrors,
formErrors: flattenedErrors?.formErrors,
formattedErrors: formattedErrors,
},
})
}
export const onboarding = authProcedure
.createServerAction()
.input(input, { type: 'formData' })
.output(input)
.handler(async ({ input, ctx: { user } }) => {
await validateUniqueUsername({ data: input, user })
const result = await finishOnboarding({ user, data: input })
const value = result.unwrap()
// NOTE: This ends in JWT callback in auth/index.ts
await updateSession({
user: { name: value.name, username: value.username },
})
redirect('/')
})
Hey,
Thanks for implementing the experimental global shapeError
method, this is exactly what I needed. What's the best way to customise the OpenAPI error code (returns 500 by default). Should you use status
if the property is in the error returned by shapeError
?
{
"type": "NotFound",
"status": 404,
"message": "Organization not found"
}
This way you could remove shapeError
from the router possibly.
i am trying your example from the docs:
export const produceNewMessage = createServerAction()
.input(
z.object({
name: z.string().min(5),
}),
{
type: "formData",
}
)
.handler(async ({ input }) => {
await new Promise((resolve) => setTimeout(resolve, 500))
return "Hello, " + input.name
})
it seems that when removing the return statement, the isSuccess is never true it is always false, is this the intended behavior ?
I am using zsa-react-query
on the client and while working with the library I needed to mutate the data, when I started inserting queryKey I noticed that the key types with createServerActionsKeyFactory
are not supported. I looked in the source code and didn't see a type reference:
zsa/packages/zsa-react-query/src/index.ts
Lines 47 to 49 in d3a9a15
zsa/packages/zsa-react-query/src/index.ts
Lines 166 to 175 in d3a9a15
I think this would be useful, since mutation involves modifying and invalidating the react-query cache.
https://tanstack.com/query/v4/docs/framework/react/reference/useMutation
"zsa": "0.5.0",
"zsa-react": "0.2.2",
"zsa-react-query": "0.2.0",
This is more of a feature request than an issue. I used a hook from the project, kirimase, useValidatedForm, please find this code below:
"use client";
import { FormEvent, useState } from "react";
import { ZodSchema } from "zod";
type EntityZodErrors<T> = Partial<Record<keyof T, string[] | undefined>>;
export function useValidatedForm<Entity>(insertEntityZodSchema: ZodSchema) {
const [errors, setErrors] = useState<EntityZodErrors<Entity> | null>(null);
const hasErrors =
errors !== null &&
Object.values(errors).some((error) => error !== undefined);
const handleChange = (event: FormEvent<HTMLFormElement>) => {
const target = event.target as EventTarget;
if (
target instanceof HTMLInputElement ||
target instanceof HTMLSelectElement ||
target instanceof HTMLTextAreaElement
) {
if (!(target instanceof HTMLInputElement && target.type === "submit")) {
const field = target.name as keyof Entity;
const result = insertEntityZodSchema.safeParse({
[field]: target.value,
});
const fieldError = result.success
? undefined
: result.error.flatten().fieldErrors[field];
setErrors((prev) => ({
...prev,
[field]: fieldError,
}));
}
}
};
return { errors, setErrors, handleChange, hasErrors };
}
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 like useServerAction
has access to the schema, could it not also handle something like this and return a handFormChange
and a handleInputChange
function? In this case, the handleFormChange
change could perform similar to this hook and validate each input on change and the handeInputChange
could also be applied to individual input like handleInputChange('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 use zsa-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.
Hey, I've implemented the openapi example and it returns text/plain;charset=UTF-8
as the default content-type
, should this default to application/json
and how to overirde please?
Would you consider changing the path param name in routes to use :
instead of {}
which is consistent with nextjs and other framework naming convention?
/api/:organizationId
instead of /api/{organizationId}
When using the procedure and server action below I get the following error:
Error: A "use server" file can only export async functions, found object.
I read this issue on next.js about the export for a 'use server' file must be a async function but after updating to the latest version of next.js I am still getting the error.
"next": "14.2.4",
"zsa": "^0.5.0",
"zsa-react": "^0.2.2"
"use server";
import { notFound } from "next/navigation";
import { z } from "zod";
import authedProcedure from "../procedures/authed";
const productSchema = z.object({
product_group: z.string(),
url_slug: z.string(),
});
const getProductProcedure = authedProcedure
.createServerAction()
.input(z.object({ slug: z.string() }))
.output(productSchema)
.handler(async ({ input, ctx }) => {
const response = await fetch(``).then(r => r.json());
const product = await productSchema.parseAsync(response.results?.at(0));
if (product) notFound();
return product;
});
export default getProductProcedure;
"use server";
import { createServerActionProcedure, ZSAError } from "zsa";
import { currentUser } from "@clerk/nextjs/server";
const authedProcedure = createServerActionProcedure().handler(async () => {
try {
const user = await currentUser();
return {
user
};
} catch {
throw new ZSAError("NOT_AUTHORIZED", "User is not authenticated");
}
});
export default authedProcedure;
Not really an issue. But a piece of feedback ๐
While working in this PR #124 I noticed CI is not running Linter or Typescript checks.
Is there any reason for that?
Also notice ESLint config is a big convoluted with double tsconfig.json
and tsconfig.lint.json
in all the packages. I think this could be simplified.
I admit this one is not critical ๐ . But I've working in all my monorepos with pnpm is so much better experience. Faster builds and better module resolution.
Hi, I'm Using ZSAError() to Handle Errors. In the action I want to send error code "INSUFFICIENT_CREDITS" to the client. I know there are others way of achieving the same but was wondering if I can modify the types of the codes in ZSAError
Error when trying to insert the result of the createServerActionProcedure
function into useServerActionMutation
.
Argument of type 'CompleteProcedure<ZodObject<{ test: ZodString; }, "strip", ZodTypeAny, { test: string; }, { test: string; }>, THandlerFunc<ZodObject<{ test: ZodString; }, "strip", ZodTypeAny, { test: string; }, { test: string; }>, undefined, "ShapeErrorNotSet", Promise<void>, undefined, "json", true>, "ShapeErrorNotSet">' is not assignable to parameter of type 'TAnyZodSafeFunctionHandler'
import { z } from "zod";
import { createServerActionProcedure } from "zsa";
const TestAction = createServerActionProcedure()
.input(z.object({ test: z.string() }))
.handler(async () => {
return;
});
export const test = createServerActionProcedure(TestAction).handler(
async () => {
return;
},
);
const mutation = useServerActionMutation(test) // Error
"zsa": "0.5.0",
"zsa-react": "0.2.2",
"zsa-react-query": "0.2.0",
It would be nice to be able to pass multiple arguments to the server action, this would make it easier to pass additional arguments with the bind
method as this can be done with server actions normally.
For reference: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#passing-additional-arguments
I am new to using ZSA and would like to know if there is a way to merge multiple procedures into a single procedure when creating an action.
I would like to know how to deal with formData when using the useServerAction hook in the onSubmit of a form. I am sharing a common Zod schema between the client and server. When dealing with an array of objects, I stringify them and use formData.append. However, the createServerAction() .input(POST_SCHEMA, { type: 'formData' })
validates the input against the Post schema, causing a Zod error since the types are different. What is the best way to handle this?
I'm getting the error "Invalid opts, must originate from the server" when generating the specs from the server, most likely a change in my code but I can't figure out the reason. When would this error happen please?
I am checking if the request has come from a certain IP address. However, when creating a procedure, the request is always undefined even though it is typed to be available.
createServerActionProcedure().handler(
async ({ request }) => {
if (!request) {
console.log('no request')
throw new ZSAError('NOT_AUTHORIZED')
}
I am trying to submit a form but I am getting this error from nextjs Error: Invalid Server Actions request.
.
I am on Next.JS 14.2.4.
This is my code for my action and form.
// page.tsx
import { TestForm } from './Form'
export default function Page() {
return (
<div>
<TestForm />
</div>
)
}
// Form.tsx
'use client'
import { useServerAction } from 'zsa-react'
import { signInAction } from '@/lib/actions/auth'
export const TestForm = () => {
const { isPending, executeFormAction, data, error } =
useServerAction(signInAction)
return (
<form action={executeFormAction}>
<input name="email" type="email" />
<input name="password" type="password" />
<button disabled={isPending}>Submit</button>
</form>
)
}
// lib/actions/auth.ts
'use server'
import z from 'zod'
import { createServerAction } from 'zsa'
export const signInAction = createServerAction()
.input(
z.object({
email: z
.string({ required_error: 'Email is required' })
.email('Must be a valid email address'),
password: z
.string({ required_error: 'Password is required' })
.min(8, 'Must be at least 8 characters')
.max(64, 'Must not exceed 64 characters'),
}),
{ type: 'formData' },
)
.handler(async ({ input }) => {
// Sleep for .5 seconds
await new Promise((resolve) => setTimeout(resolve, 500))
// Increment the input number by 1
return 'I have not been implemented yet, please wait for a while'
})
Also, I am seeing this in the browser dev tools when I check my form:
Hello! We just found this library a couple of weeks ago and have started trying to implement it into our application where we heavily use server actions. We ran into a case that the documentation does not mention so we are hoping there is an answer.
We have several cases in our server actions where we need to call FormData.getAll to get all inputs instead of FormData.get. How can we do this with this library?
For instance, we might have the code in the server action that looks like this:
const result = zodSchema.safeParse({
...Object.fromEntries(formData),
files: formData.getAll('files'),
});
I have a zod array as an input property type, ie: input(z.object({ list: z.array(z.string()) }))
.
When using openapi with a GET, is there a way to pass list as an array via querystring? Something like list[]=foo&list[]=bar
or list=foo&list=bar
?
Thanks!
Create a good CONTRIBUTING.md
In the context of using input
with type="state"
and invalid values with progressive enhancement in mind, is there a way of getting these (invalid) values to pass it for instance as defaultValues
in RHF
(in that way, the form can be filled with the values during server rendering even if javascript is disabled)?
actions.ts
"use server"
export const subscribeToNewsletterAction = createServerAction()
.input(zNewsletterValues, {type: "state"})
.handler(async ({input: {email}}) => subscribeToNewsletter(email))
newsletter-form.tsx
"use client"
export default function NewsletterForm() {
const [[data, error], action, pending] = useActionState(subscribeToNewsletterAction, [null, null])
const form = useForm<NewsletterValues>({
mode: "onTouched",
resolver: zodResolver(zNewsletterValues),
defaultValues: ... // error?.values or similar
})
For now, my workaround is to create an extra function like the one in custom state
when I can access formData
directly and pass it through:
actions.ts
"use server"
const subscribeToNewsletterZSA = createServerAction()
.input(zNewsletterValues, {type: "state"})
.handler(async ({input: {email}}) => subscribeToNewsletter(email))
export const subscribeToNewsletterAction = async (
_prev: NewsletterState,
formData: FormData
): Promise<NewsletterState> => {
const [data, error] = await subscribeToNewsletterZSA(formData)
if (data) return [data, null]
const values = Object.fromEntries(formData.entries()) as NewsletterValues
return [null, {...error, values}]
}
Hello guys, very cool lib!
I don't know if I'm doing something wrong, but I can't get isPending
updated and status
never gets to pending
.
Am I missing something?
Reproduction: https://codesandbox.io/p/devbox/zsa-ispending-problem-rhdvmm
We were working in monorepo and ran into the multiversion problem when trying next-rc
next-rc package.json:
"dependencies": {
"next": "^15.0.0-rc.0",
"react": "^19.0.0-rc",
"react-dom": "^19.0.0-rc",
"zod": "^3.23.8",
"zsa": "^0.4.0",
"zsa-react": "^0.1.9"
}
run yarn list
:
yarn list zod:
โโ [email protected]
โ โโ [email protected]
โโ [email protected] // This is the version the other local packages are using
โโ [email protected]
โ โโ [email protected]
โโ [email protected]
โโ [email protected]
yarn list react:
โโ [email protected]
โ โโ [email protected]
โโ [email protected]
โโ [email protected]
From reading the docs, some may think that you need useServerAction
's execute method to call actions in the client. We should add an example that shows you don't need it and can just call it directly.
Cases where a formData
is passed with multiple entries with the same field name are not handled, so if we pass a formData to the server action that had several formData.append("name")
on the client we will only get the last entry. Libs like zod-form-data handle this case automatically by turning the filed into an array.
I can provide more info if necessary, and If this is already possible, please correct me!
I don't want to post it here for obvious reasons and your twitter DMs are closed. Can you DM me?
Using the errors object, the key "fieldErrors" is returned flattened (here).
If these could be the keyed fieldErrors zod returns before flattening, it would be more possible to display each error on the correct place.
Add docs for the following helper types
inferServerActionReturnData
inferServerActionReturnType
inferServerActionInput
Is there a reason why the NextRequest
type is different than the one from next/server
? Can we export the type in https://github.com/IdoPesok/zsa/blob/5e1fbc7dc8221ad9c1d97cf751c3e80031822fd5/packages/zsa/src/types.ts please?
I want to reuse a procedure handler to have a conditional procedure and want it to be typesafe (unless you recommend a different approach)
Thanks!
Issue: execute async function never fulfilled
when it invoked inside startTransition
cb.
In this example I log all statuses into console.
When i invoked execute
fn inside startTransition
cb isPending
(from useTransition) always true and loader never ending...
~console.log:
status idle
START
status pending
status pending
but when i replacing execute
with executeFormAction
|| or use action directly โ everything works great...
~console.log:
status idle
START
status pending
status pending
status success
SUCCESS
FINISHED
I need useTransition
to handle redirecting process router.push(/blog/${post.slug});
...
// Example
export const EditPostForm: RC<IProps> = (props) => {
const router = useRouter();
const [isPending, startTransition] = useTransition();
const { execute, status } = useServerAction(updatePost, {
onStart: () => {
console.log('START');
},
onSuccess: () => {
console.log('SUCCESS');
},
onError: (error) => {
console.log('ERROR', error);
},
onFinish: () => {
console.log('FINISHED');
},
});
console.log('status', status);
return (
<PostForm
loading={isPending}
onSubmit={async (values) => {
startTransition(async () => {
const [post] = await execute({ id, values });
if (!post) return;
router.push(`/blog/${post.slug}`);
});
}}
/>
);
};
In our current docs it says to do:
createServerAction().input(...)
or
myProcedure.createServerAction().input(...)
But the problem is could be better DX to not have to write createServerAction
everytime and just do something like this
const publicAction = createServerAction()
const authAction = createServerActionProcedure()...createServerAction()
const action1 = publicAction.input(...)
const action2 = authAction.input(...)
Hello,
I'm trying to use zsa on a form with javascript disabled but it does not seem to work. Is progressive enhancement manageable with zsa?
It would be nice if the docs has a search bar. I'd recommend looking into Fuma docs https://fumadocs.vercel.app/. It was easy to setup and has build in search functionality.
I am not sure if this is something not doable, thus a request, or something that I am doing wrong.
First, I create an server action using a procedure that requires the admin role
I end the function with .createServerAction();
export const createProductAction = createServerActionProcedure(adminProcedure)
.input(createProductSchema)
.handler(async ({ input }) => {
try {
const { error } = await db.from("products").insert([
{
name: input.name,
},
]);
} catch (error) {
throw new Error("An error as occured");
}
})
.createServerAction();
Then, in my client form CreateProduct
, I want to use the useServerAction
hook and deconstruct the props to handle the states.
But I have a TS error on createProductAction
, in that line:
const {isPending,data,execute,isError}=useServerAction(createProductAction)
and can't actually use that file.
What am I doing wrong?
I am so sorry if this is not the right place for this request.
Hi, I'm using useServerAction
to save some data into my server. It's working fine but I see a glitch while isPending
The errors in the server are reset and the UI jumbs.
This is my form:
const { data, executeFormAction, isPending, error, ...rest } = useServerAction(
onboarding,
{
initialData: { name, username },
},
)
const errorData = error?.data
const fieldErrors = error?.fieldErrors
return (
<Input
label='Your username'
type='text'
name='username'
errors={fieldErrors?.username}
defaultValue={data?.username ?? errorData?.username}
onChange={(e) => setUserName(e.target.value)}
placeholder='Pick a username'
description={<UsernameDescription username={currentUsername} />}
/>
)
This is my action:
export const onboarding = authProcedure
.createServerAction()
.input(input, { type: 'formData' })
.output(input)
.experimental_shapeError(({ err, typedData }) => {
if (err instanceof ZSAError && err.code !== 'INPUT_PARSE_ERROR') {
return {
code: err.code,
message: err.message,
}
}
return {
data: typedData?.inputRaw,
fieldErrors: typedData?.inputParseErrors?.formattedErrors,
}
})
.handler(async ({ input, ctx: { user } }) => {
await validateUniqueUsername({ data: input, user })
const result = await finishOnboarding({ user, data: input })
const value = result.unwrap()
await updateSession({
user: { name: value.name, username: value.username },
})
redirect('/')
})
This is my UI. Check the disappearing red errors when submitting
I have defined a Zod Schema and the type: formData, but i need to add additional parameters to the server action. I used Bind on the method before transitioning to ZSA, but it does not seem to work. I can't figure out if it's supported or not, do we have a way to do add additional parameters ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.