I try to build a dynamic form with react-hook-form and yup by this cool guide: https://dev.to/franklin030601/dynamic-forms-with-react-hook-form-2ml8
i have this structure of data:
export const tabs: Tab[] = [
{
tabContent: [
{
label: 'Размер',
name: 'productSize',
placeholder: '35 px',
sizeVariant: '15',
type: 'text',
validations: [
{
message: 'Минимум 3 символа',
type: 'minLength',
value: 3
},
{
message: 'Обязательно к заполнению',
type: 'required'
}
],
value: ''
},
],
tabTitle: 'Лендинг'
},
{
tabContent: [
{
label: 'Terms and Conditions',
name: 'terms4',
type: 'checkbox',
typeValue: 'boolean',
validations: [
{
message: 'Accept the terms!',
type: 'isTrue'
}
],
value: true
},
{
groupTitle: 'Group 1',
inputs: [
{
label: 'Terms',
name: 'terms2',
type: 'checkbox',
typeValue: 'boolean',
validations: [
{
message: 'Accept the terms!',
type: 'isTrue'
}
],
value: true
},
{
label: 'Checkbox 2',
name: 'checkbox2',
type: 'checkbox',
typeValue: 'boolean',
value: true
},
{
label: 'Checkbox 3',
name: 'checkbox3',
type: 'checkbox',
typeValue: 'boolean',
value: false
}
]
}
],
tabTitle: 'Системное'
}
]
I process validation fields here:
type YupBoolean = Yup.BooleanSchema<boolean | undefined, Yup.AnyObject, boolean | undefined>
type YupString = Yup.StringSchema<string | undefined, Yup.AnyObject, string | undefined>
type YupNumber = Yup.NumberSchema<boolean | undefined, Yup.AnyObject, number | undefined>
/** обработчик валидаций yup */
const generateValidations = (field: InputTypes) => {
if (!field.validations) return null
/** задает схему */
let schema: YupBoolean | YupString = Yup[field.typeValue || 'string']()
for (
/** пробегается по правилам из данных validations */
const rule of field.validations) {
switch (rule.type) {
case 'isTrue' : schema = (schema as YupBoolean).isTrue(rule.message); break
case 'isEmail' : schema = (schema as YupString).email(rule.message); break
case 'minLength': schema = (schema as YupString).min(rule?.value as number, rule.message); break
case 'oneOf' : schema = (schema as YupString).oneOf([Yup.ref((rule as any).ref)], rule.message); break
default : schema = schema.required(rule.message); break
}
}
return schema
}
I then try to spread form into tabs with react-tabs:
/** страница тестовая */
const TestPage = () => {
/** дата */
const anotherForm = transformForm(tabs)
console.log('anotherForm.validationsFields', anotherForm.validationsFields)
/** методы из формы */
const formMethods = useForm({
defaultValues: { ...(anotherForm.initialValues as any) },
mode: 'onSubmit',
resolver: yupResolver(anotherForm.validationsFields)
})
/** обработчик сабмита */
const onSubmit = (data) => {
console.log('data', data)
}
return (
<section>
<FormProvider {...formMethods}>
<form
className=''
onSubmit={formMethods.handleSubmit(onSubmit)}
>
<Tabs>
<TabList>
{anotherForm.tabs.map((tab, index) => (
<Tab key={index}>
{tab.tabTitle}
</Tab>
))}
</TabList>
{anotherForm.tabs.map((tab, index) => (
<TabPanel key={index}>
<>
<h2>
{tab.tabTitle}
</h2>
<Form tabContent={tab.tabContent} />
</>
</TabPanel>
))}
</Tabs>
<button type='submit'>
submit
</button>
<TabsUnderline />
</form>
</FormProvider>
</section>
validation schema looks like this: schema after processing
Everything works fine if i dont try to put fields in tabs and make 1 long page with all fields, or if i turn off resolver. But if i try to switch between tabs, i get error
**TypeError: o[(intermediate value)(intermediate value)(intermediate value)] is not a function**
As i understand, this is something to be with context in useForm, or schemas context. I could not manage to solve it.
Another question: i need to save entered data locally by switching the tabs, get backend data by reloading the page and send entered data to the server only by clicking submit button. I dont want to use any state manager. Do i use react-hook-form in the right way here?