I am fairly new to React (but have coded in JavaScript and C# for 20 plus years). I have a vanilla form using hook-form, react-bootstrap, zod and flowbite-react. There are two nearly identical functions: create and update. The create function works correctly, but the update form incorrectly validates the two required inputs. The first time the submit button is selected, I get validation errors on both required inputs; the second time just the second required input and the third time it works and the update is sent back to the server. Both input controls have text in them.
export const MembershipUpdate = () => {
const [membership, setMembership] = useState(
{
id: 0,
firstName: '',
lastName: '',
fullName: '',
shortname: '',
nickName: '',
wheelchair: false
}
);
const location = useLocation();
const id: number = location.state;
const {
register,
handleSubmit,
formState: { errors },
} = useForm<UpdateFormData>({
resolver: zodResolver(UpdateFormDataSchema),
});
const onSubmit: SubmitHandler<UpdateFormData> = (data) =>updateData(data) // send updated record to server
const navigate = useNavigate();
function OnChange(e: React.ChangeEvent<HTMLInputElement>) {
setMembership({ ...membership, [e.target.name]: e.target.value });
}
function OnChecked(e: React.ChangeEvent<HTMLInputElement>) {
setMembership({ ...membership, [e.target.name]: e.target.checked });
}
useEffect(() => {
GetData(); // get original record from server
}, []);
const contents = membership === undefined
? <p><em>Loading ...</em></p> :
<form onSubmit={handleSubmit(onSubmit)} >
<input type="hidden" {...register("id", { valueAsNumber: true })} value={membership.id} />
<TextInput {...register("nickName")} type="hidden" />
<TextInput {...register("fullName")} type="hidden" />
<Container >
<Row>
<Col style={{ width: '15%' }}><Label>First Name:</Label></Col>
<Col><TextInput type="text" {...register('firstName')} style={{ width: '85%' }} value={membership.firstName} onChange={OnChange} /></Col>
</Row>
<Row>
<Col style={{ width: '15%' }}><Label>Last Name:</Label></Col>
<Col><TextInput {...register('lastName')} style={{ width: '85%' }} value={membership.lastName} onChange={OnChange} /></Col>
</Row>
<Row>
<Col style={{ width: '15%' }}><Label>Short Name:</Label></Col>
<Col><TextInput {...register('shortname')} style={{ width: '85%' }} value={membership.shortname} onChange={OnChange} /></Col>
</Row>
<Row>
<Col style={{ width: '15%' }}><Label>Wheel Chair:</Label></Col>
<Col style={{ textAlign: "left", width: '85%' }}>
<Checkbox {...register('wheelchair')}checked={membership.wheelchair} onChange={OnChecked} /></Col>
</Row>
<Row>
<Col style={{ textAlign: "center", width: '100%' }}>
<TextInput type="submit" />
</Col>
</Row>
{errors.firstName && <p className="errorMessage">{errors.firstName.message}</p>}
{errors.lastName && <p className="errorMessage">{errors.lastName.message}</p>}
{errors.shortname && <p className="errorMessage">{errors.shortname.message}</p>}
</Container>
</form>
return (
<>
<h1>Update record</h1>
{contents}
</>
);
}
The schema and data format is defined as:
import { z } from 'zod';
export const UpdateFormDataSchema = z.object({
id: z.number(),
firstName: z.string().min(1, "First Name is required").max(50, "First Nmme has a maximum of 50 characters"),
lastName: z.string().min(1, "Last Name is required").max(50, "Last Nmme has a maximum of 50 characters"),
fullName: z.string(), // computed column in DB
shortname: z.string().max(25, "Short Nmme has a maximum of 25 characters"),
nickName: z.string(), //computed column in DB
wheelchair: z.boolean()
});
export type UpdateFormData = z.infer<typeof UpdateFormDataSchema>;