Search code examples
next.jsreact-hook-formshadcnui

Server Actions in Client Component Next.js


I need to run some server actions on a client component because the shadcn/ui <Form> component requires it. I am referencing docs from shadcn/ui and Lucia. shadcn/ui uses react-hook-form and zod.

Here's my code:

'use client'

// imports

const registerFormSchema = // zod schema

export default function Register() {
    const form = useForm<z.infer<typeof registerFormSchema>>({
        resolver: zodResolver(registerFormSchema)
    })

    return (
          <Form {...form}>
              <form onSubmit={register}>
                  <CardHeader>
                      <CardTitle>Register</CardTitle>
                  </CardHeader>
                  <CardContent className={"formContent"}>
                      <FormField
                            control={form.control}
                            name="name"
                            render={({ field }) => (
                                  <FormItem className={"formItem"}>
                                      <FormLabel>Name</FormLabel>
                                      <FormControl>
                                          <Input type={"name"} {...field} />
                                      </FormControl>
                                      <FormMessage />
                                  </FormItem>
                            )}
                      />
                      // other form fields (email, password)
                  </CardContent>
                  <CardFooter className={"flex justify-between"}>
                      // buttons
                  </CardFooter>
              </form>
          </Form>
    );
}

async function register(values: z.infer<typeof registerFormSchema>): Promise<ActionResult> {
    'use server';

    const result = registerFormSchema.safeParse(values);
    if (!result.success) {
        return { error: result.error.message }
    }

    const user = prisma.user.create(
          {
              data: {
                  name: values.name,
                  email: values.email,
                  password: values.password // dw ill hash it later
              }
          }
    )

    user.then(async (value) =>  {
        const session = await lucia.createSession(value.id, {});
        const sessionCookie = lucia.createSessionCookie(session.id);
        cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
    })

    return redirect("/dashboard");
}

With 'use client' at the top: You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component. Without 'use client' at the top: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it.

I also tried putting the register function in another file, but that broke React hook rules.

This is not my first time running into large roadblocks with react-hook-forms and I'm pretty sure I'm missing something fundamental to do with react forms or just Next.js in general.


Solution

  • <form onSubmit={form.handleSubmit((value) => register(value))}>
    

    instead of

    <form onSubmit={register}>