/
githubmirror
/
trpc
Обзор
Документация
Войти
/
githubmirror
/
trpc
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
examples/next-formdata/src/pages/react-hook-form.tsx
133 строки
4 KB
Alex / KATT
chore(deps): bump zod + react-hook-form (#7074)
23 дек 2025, 18:03
Не верифицирован
23 дек 2025, 18:03
f48ed5c
Код
Авторство
О чём код?
import { zodResolver } from '@hookform/resolvers/zod'; import { uploadFileSchema } from '~/utils/schemas'; import { trpc } from '~/utils/trpc'; import { useRef, useState } from 'react'; import type { FieldValues, UseFormProps, UseFormReturn } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form'; import type { z } from 'zod'; type ZodFormData<TSchema extends FieldValues> = UseFormReturn<TSchema> & { formRef: React.RefObject<HTMLFormElement | null>; }; function useZodForm<TInput extends FieldValues>( props: Omit<UseFormProps<TInput>, 'resolver'> & { schema: z.ZodType<TInput, any>; }, ) { const _resolver = zodResolver(props.schema, undefined, { raw: true, }); const form = useForm<TInput>({ ...props, resolver: (_values, ctx, opts) => { if (!form.formRef.current) { return { values: {}, errors: { root: { message: 'Form not mounted', }, }, }; } const values = new FormData(form.formRef.current); return _resolver(values as any, ctx, opts) as any; }, }) as ZodFormData<TInput>; form.formRef = useRef<HTMLFormElement>(null); return form; } export default function Page() { const mutation = trpc.room.sendMessage.useMutation({ onError(err) { alert('Error from server: ' + err.message); }, }); const form = useZodForm({ schema: uploadFileSchema, defaultValues: { name: 'whadaaaap', }, }); const [noJs, setNoJs] = useState(false); return ( <> <h2 className="text-3xl font-bold">Posts</h2> <FormProvider {...form}> <form method="post" action={`/api/trpc/${mutation.trpc.path}`} encType="multipart/form-data" onSubmit={(_event) => { if (noJs) { return; } void form.handleSubmit(async (values, event) => { await mutation.mutateAsync(new FormData(event?.target)); })(_event); }} style={{ display: 'flex', flexDirection: 'column', gap: 10 }} ref={form.formRef} > <fieldset> <legend>Form with file upload</legend> <div style={{}}> <label htmlFor="name">Enter your name</label> <input {...form.register('name')} /> {form.formState.errors.name && ( <div>{form.formState.errors.name.message}</div> )} </div> <div> <label>Required file, only images</label> <input type="file" {...form.register('image')} /> {form.formState.errors.image && ( <div>{form.formState.errors.image.message}</div> )} </div> <div> <label>Post without JS</label> <input type="checkbox" checked={noJs} onChange={(e) => { setNoJs(e.target.checked); }} /> </div> <div> <button type="submit" disabled={mutation.status === 'pending'}> submit </button> </div> </fieldset> </form> {mutation.data && ( <fieldset> <legend>Upload result</legend> <ul> <li> Image: <br /> <img src={mutation.data.image.url} alt={mutation.data.image.url} /> </li> </ul> </fieldset> )} </FormProvider> </> ); }