Form is somehow getting server rendered? RHF
Hi all,
Currently porting my Next JS app to Start but running into issues with my form component. When I console log form, it get's logged in the terminal. I'm assuming this may have to do with how my route is set up, but I'm not sure how to adjust.
I appreciate any advice.
route file
import { createFileRoute } from '@tanstack/react-router';
import CreateAnAccountForm from '../../components/feat/accounts/create-an-account/create-an-account-form';
export const Route = createFileRoute('/onboarding/')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div className="flex min-h-screen w-full flex-col items-center justify-center p-4">
<div className="mx-auto w-full max-w-md">
<CreateAnAccountForm />
</div>
</div>
);
}
import { createFileRoute } from '@tanstack/react-router';
import CreateAnAccountForm from '../../components/feat/accounts/create-an-account/create-an-account-form';
export const Route = createFileRoute('/onboarding/')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div className="flex min-h-screen w-full flex-col items-center justify-center p-4">
<div className="mx-auto w-full max-w-md">
<CreateAnAccountForm />
</div>
</div>
);
}
4 Replies
solid-orangeOP•3mo ago
Form component file
continued
Continued
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import z from 'zod';
import { useState } from 'react';
import { Button } from '@workspace/ui/components/button';
import { Form } from '@workspace/ui/components/form/form';
import {
TextInput,
RadioInputGroup,
} from '@workspace/ui/components/form/inputs';
import { InputsWrapper } from '@workspace/ui/components/form/wrappers';
import { useUser } from '@clerk/tanstack-react-start';
import { useMutation } from 'convex/react';
import { api } from '../../../../../convex/_generated/api';
import { useRouter } from '@tanstack/react-router';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@workspace/ui/components/card';
const INTEREST_OPTIONS = [
{ value: 'vendor', label: '出店者になりたい' },
{ value: 'organizer', label: 'マルシェの主催者になりたい' },
{ value: 'both', label: '両方になりたい' },
];
const formSchema = z.object({
name: z.string().min(1, { message: 'マルシェの名前を入力してください' }),
interest: z.enum(
INTEREST_OPTIONS.map((option) => option.value) as [string, ...string[]]
),
});
type CreateAnAccountFormValues = z.infer<typeof formSchema>;
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import z from 'zod';
import { useState } from 'react';
import { Button } from '@workspace/ui/components/button';
import { Form } from '@workspace/ui/components/form/form';
import {
TextInput,
RadioInputGroup,
} from '@workspace/ui/components/form/inputs';
import { InputsWrapper } from '@workspace/ui/components/form/wrappers';
import { useUser } from '@clerk/tanstack-react-start';
import { useMutation } from 'convex/react';
import { api } from '../../../../../convex/_generated/api';
import { useRouter } from '@tanstack/react-router';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@workspace/ui/components/card';
const INTEREST_OPTIONS = [
{ value: 'vendor', label: '出店者になりたい' },
{ value: 'organizer', label: 'マルシェの主催者になりたい' },
{ value: 'both', label: '両方になりたい' },
];
const formSchema = z.object({
name: z.string().min(1, { message: 'マルシェの名前を入力してください' }),
interest: z.enum(
INTEREST_OPTIONS.map((option) => option.value) as [string, ...string[]]
),
});
type CreateAnAccountFormValues = z.infer<typeof formSchema>;
export default function CreateAnAccountForm() {
const { user } = useUser();
const [isSubmitting, setIsSubmitting] = useState(false);
const form = useForm<CreateAnAccountFormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
name: '',
interest: undefined,
},
});
const createAccount = useMutation(api.accounts.createAccount);
const router = useRouter();
const onSubmit = async (values: CreateAnAccountFormValues) => {
setIsSubmitting(true);
try {
const userId = user?.id;
if (!userId) throw new Error('User not found');
const account = await createAccount({
name: values.name,
creatorUserId: userId,
});
router.navigate({ to: `/a/${account}` });
} catch (err: any) {
console.error(err);
alert(err.message || 'アカウントの作成に失敗しました');
} finally {
setIsSubmitting(false);
}
};
console.log(form);
return (
<div className="flex min-h-screen w-full flex-col items-center justify-center p-4">
<div className="mx-auto w-full max-w-md">
<Card className="w-full">
<CardHeader className="text-center">
<CardTitle className="text-2xl">Marche OSへようこそ</CardTitle>
<CardDescription>
アカウントの設定を完了しましょう。
</CardDescription>
</CardHeader>
<CardContent>
<Form form={form} onSubmit={onSubmit}>
<InputsWrapper>
<TextInput form={form} name="name" label="アカウント名" />
<RadioInputGroup
form={form}
name="interest"
label="興味のある分野"
options={INTEREST_OPTIONS}
variant="vertical"
/>
</InputsWrapper>
export default function CreateAnAccountForm() {
const { user } = useUser();
const [isSubmitting, setIsSubmitting] = useState(false);
const form = useForm<CreateAnAccountFormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
name: '',
interest: undefined,
},
});
const createAccount = useMutation(api.accounts.createAccount);
const router = useRouter();
const onSubmit = async (values: CreateAnAccountFormValues) => {
setIsSubmitting(true);
try {
const userId = user?.id;
if (!userId) throw new Error('User not found');
const account = await createAccount({
name: values.name,
creatorUserId: userId,
});
router.navigate({ to: `/a/${account}` });
} catch (err: any) {
console.error(err);
alert(err.message || 'アカウントの作成に失敗しました');
} finally {
setIsSubmitting(false);
}
};
console.log(form);
return (
<div className="flex min-h-screen w-full flex-col items-center justify-center p-4">
<div className="mx-auto w-full max-w-md">
<Card className="w-full">
<CardHeader className="text-center">
<CardTitle className="text-2xl">Marche OSへようこそ</CardTitle>
<CardDescription>
アカウントの設定を完了しましょう。
</CardDescription>
</CardHeader>
<CardContent>
<Form form={form} onSubmit={onSubmit}>
<InputsWrapper>
<TextInput form={form} name="name" label="アカウント名" />
<RadioInputGroup
form={form}
name="interest"
label="興味のある分野"
options={INTEREST_OPTIONS}
variant="vertical"
/>
</InputsWrapper>
<Button
type="submit"
className="min-w-32"
size="lg"
disabled={isSubmitting}
>
{isSubmitting ? '送信中...' : 'アカウントを作成'}
</Button>
</Form>
</CardContent>
</Card>
</div>
</div>
);
}
<Button
type="submit"
className="min-w-32"
size="lg"
disabled={isSubmitting}
>
{isSubmitting ? '送信中...' : 'アカウントを作成'}
</Button>
</Form>
</CardContent>
</Card>
</div>
</div>
);
}
quickest-silver•3mo ago
Your code will definitely log once in the terminal because Start is SSR
you can call
console.log(form);
in onSubmit
functionsolid-orangeOP•3mo ago
Currently I can’t even call the onSubmit function and none of the RHF validation is working when I try to submit.
quickest-silver•3mo ago
<Form> component shadcn wrap wrong.
You can wrap with
<Form {...form}
<form onSubmit={onSubmit}>
...