We use react-hook-form and zod to create the form. Here are the basic steps to create a simple form
You can set error message with i18n, you can read this file to learn about i18n
import { z as zod } from 'zod'
export function ComponentForm() {
const t = useComponentI18N() // Set errror messge with i18n.
const schema = zod.object({
name: zod.string(), // string
age: zod.number(t.needBeNumber()).positive(t.needGreaterThanZero()), // > 0
country: zod.string(t.countyNeedBeString()).optional(), // string | undefiend
address: zod
.string()
.min(1)
.refine((address) => ValidAddress(address), t.InvalidAddress), // You can use other methods to validate this field
})
// ...
}import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
const methods = useForm<formType>({
resolver: zodResolver(schema),
defaultValues: {
name: '',
age: 1,
address: '',
},
})react-hook-form provides optional argumenjs, you can change it on demand.
The react-hook-form provides the Controller component without import other packages to support UI libraries
const {
control,
handleSubmit,
formState: { errors, dirtyFields, isDirty },
} = useForm(options)
const onSubmit = handleSubmit((data) => doSomething())
return (
<form>
<Controller
render={({ field }) => <TextField {...field} helperText={errors.name?.message} error={dirtyFields.name} />}
name="name"
/>
<Button onClick={onSubmit} disabled={!isValid} />
</form>
)In practice, you may need to get form methods in the children component. You can use useFormContext and FormProvider to resolve this problem.
// Parent component
const methods = useForm()
return <FormProvider {...methods}>....</FormProvider>
// Children component
const { control, register, formState } = useFormContext()Sometimes we need set some field from remote data. You can use setValue to change these field. If you want to trigger valid while setting the field, you can add the shouldValid option
const { watch, setValue } = useForm()
// You can use watch to monitor some field change
const address = watch('address')
useEffect(() => {
const { symbol } = fetchDataByAddress(address)
setValue('symbol', symbol, { shouldValid: true })
}, [address])Sometimes we need to listen to the field update to do something. Although you can use watch to react to a field. But it will cause extra renders and cause a potential performance problem. Try to use getValues if that suits you.