I am trying to conditional render the fields and submit the data.
But on the below code snippet, i am not able to achieve this. Issues are re rendering happens and the values not getting persisting.
Here mostly the problem is i am splitting the schema, so based on the selection of the choice the field renders.
How can i submit the data with proper persisting the validation and values.
What i have tried so far
App.js
import React, { useEffect, useState } from "react";
import "./styles.css";
import Select from "react-select";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers";
import { CITIZEN_OPTIONS, validationSchema } from "./util";
import { Resident, NonResident } from "./CitizenDetails";
const Fallback = () => null;
export default function App() {
const [citizenValue, setCitizenValue] = useState(null);
const { register, control, errors, watch, handleSubmit } = useForm({
resolver: yupResolver(validationSchema),
mode: "onBlur",
reValidateMode: "onChange"
});
const watchCitizen = watch("citizen");
useEffect(() => {
setCitizenValue(watchCitizen?.value);
}, [watchCitizen]);
const citizenDetails = {
resident: () => <Resident errors={errors} register={register} />,
non_resident: () => (
<NonResident errors={errors} control={control} register={register} />
)
};
const onSubmit = (data) => {
console.log(data);
};
const SelectedCitizenFields = citizenDetails[citizenValue] || Fallback;
return (
<div className="App">
<Controller
as={Select}
control={control}
name="citizen"
options={CITIZEN_OPTIONS}
></Controller>
<SelectedCitizenFields />
<button onClick={handleSubmit(onSubmit)}>Submit Details</button>
</div>
);
}
CitizenDetails.js
import React, { Fragment, memo } from "react";
import { Controller } from "react-hook-form";
import Select from "react-select";
export const Resident = memo((props) => {
const { errors, register } = props;
return (
<Fragment>
<div className="field-group">
<label>Enter first name</label>
<input ref={register} name="first_name"></input>
{errors?.first_name?.message && (
<span>{errors.first_name.message}</span>
)}
</div>
<div className="field-group">
<label>Enter last name</label>
<input ref={register} name="last_name"></input>
{errors?.last_name?.message && <span>{errors.last_name.message}</span>}
</div>
</Fragment>
);
});
export const NonResident = memo((props) => {
const { errors, register, control } = props;
return (
<Fragment>
<div className="field-group">
<label>Enter passport number</label>
<input ref={register} name="passport_number"></input>
{errors?.passport_number?.message && (
<span>{errors.passport_number.message}</span>
)}
</div>
<div className="field-group">
<label>Choose Country</label>
<Controller as={Select} control={control} name="country" options={[]} />
{errors?.country?.message && <span>{errors.country.message}</span>}
</div>
<div className="field-group">
<label>Choose State</label>
<Controller as={Select} control={control} name="state" options={[]} />
{errors?.state?.message && <span>{errors.state.message}</span>}
</div>
</Fragment>
);
});
util.js
import { object, string, number, lazy } from "yup";
export const CITIZEN_OPTIONS = [
{
label: "Resident",
value: "resident"
},
{
label: "Non-Resident",
value: "non_resident"
}
];
const required = () => "field is required";
const resident_schema = object({
first_name: string().required(required).nullable(),
last_name: string().required(required).nullable()
});
const non_resident_schema = object({
passport_number: string().required(required).nullable(),
country: object().required(required).nullable(),
state: object().required(required).nullable()
});
export const validationSchema = lazy(({ citizen }) => {
return citizen?.value === "resident" ? resident_schema : non_resident_schema;
});
Here is the codesandbox link