如何在React-hook-form的Controller中重新验证Joi.ref()?
问题描述
我有两个Controller,分别对应开始日期和结束日期,每个Controller包含月份和年份两个输入框。结束日期必须始终晚于开始日期,我使用Joi进行该验证。问题在于,react-hook-form仅在结束日期的onBlur事件时执行min(Joi.ref("startDate"))验证,而不会在开始日期的onChange或onBlur事件时触发验证。
现有代码
schema = Joi.object({ startDate: Joi.date() .raw() .format("YYYY-MM-DD") .less("now") .greater("1920-1-1"), endDate: Joi.date() .raw() .format("YYYY-MM-DD") .less("now") .min(Joi.ref("startDate")) .allow(null) }); const MonthYearInput = ({ name, checkbox }) => { const { control } = useFormContext(); const monthRef = useRef(); const yearRef = useRef(); const getOptions = (list) => { if (!list) return null; const options = list.map((item) => { return ( <option value={item.id} key={item.id}> {item.name} </option> ); }); return options; }; const getDate = () => { const year = yearRef.current.value; const month = monthRef.current.value; const formattedMonth = month < 10 ? `0${month}` : month; return `${year}-${formattedMonth}-01`; }; return ( <> <Controller control={control} name={name} defaultValue="" render={({ field, fieldState: { error } }) => { return ( <> <select className="form-select" onChange={(e) => { field.onChange(getDate()); }} onBlur={field.onBlur} ref={monthRef} name={`${name}month`} defaultValue="" > <option key="0" value="" disabled> Month </option> {getOptions(months)} </select> <input name={`${name}year`} type="number" step={1} onChange={(e) => { field.onChange(getDate()); }} onBlur={field.onBlur} ref={yearRef} placeholder="Year" /> {error?.message && <div>{error?.message}</div>} </> ); }} /> </> ); };
解决方案
核心思路是在开始日期发生变化时,手动触发结束日期字段的验证,利用react-hook-form提供的trigger方法即可实现。
修改步骤
- 从
useFormContext中解构出trigger方法 - 给开始日期的输入框绑定统一的变化处理函数,在更新字段值后触发结束日期的验证
修改后的组件代码
const MonthYearInput = ({ name, checkbox }) => { // 新增解构trigger方法 const { control, trigger } = useFormContext(); const monthRef = useRef(); const yearRef = useRef(); const getOptions = (list) => { if (!list) return null; const options = list.map((item) => { return ( <option value={item.id} key={item.id}> {item.name} </option> ); }); return options; }; const getDate = () => { const year = yearRef.current.value; const month = monthRef.current.value; const formattedMonth = month < 10 ? `0${month}` : month; return `${year}-${formattedMonth}-01`; }; return ( <> <Controller control={control} name={name} defaultValue="" render={({ field, fieldState: { error } }) => { // 统一处理输入变化,包含触发验证逻辑 const handleChange = () => { field.onChange(getDate()); // 仅当当前是开始日期字段时,触发结束日期的验证 if (name === 'startDate') { trigger('endDate'); } }; return ( <> <select className="form-select" onChange={handleChange} onBlur={field.onBlur} ref={monthRef} name={`${name}month`} defaultValue="" > <option key="0" value="" disabled> Month </option> {getOptions(months)} </select> <input name={`${name}year`} type="number" step={1} onChange={handleChange} onBlur={field.onBlur} ref={yearRef} placeholder="Year" /> {error?.message && <div>{error?.message}</div>} </> ); }} /> </> ); };
说明
当用户修改开始日期的月份或年份时,handleChange函数会先更新startDate的字段值,随后调用trigger('endDate')触发结束日期的Joi验证,确保结束日期始终晚于最新的开始日期,不影响原有验证逻辑的同时实现实时校验。
内容的提问来源于stack exchange,提问作者Watermamal
相关产品推荐
相关产品推荐

