React useState获取旧状态:React Hook Form复选框Context存值异常求助
问题
尝试使用React Hook Form创建带有条件复选框的表单,但将数据保存到Context时,React总是返回复选框的旧状态。尝试通过useEffect解决useState的异步问题,但没有效果。
代码如下:
const ContactFormMain: FunctionComponent<any> = ({ nextFormStep }) => { const { saveForm, infos } = useContext(ContactFormContext) as ContactFormDataType; const { register } = useForm({ mode: "onBlur", }) const [formUserData, setFormUserData] = useState<IContactFormData | {}>(infos[0]); const [val, setVal] = useState(false) const [sharingChoice, setSharingChoice] = useState<string>(infos[0].sharePatientInfo) useEffect(() => { console.log(sharingChoice) console.log(val) }, [sharingChoice, val]) const updateContext = (e: FormEvent<HTMLButtonElement | HTMLTextAreaElement | HTMLInputElement>): void => { console.log('afterSetState', formUserData); setFormUserData({ ...formUserData, [e.currentTarget.id]: e.currentTarget.value }) } const handleCheck = (e: ChangeEvent<HTMLInputElement>): void => { console.log(e.target.checked) setVal(!val) if(val === true) { setSharingChoice("Des informations concernant le patient sont transmises dans ce ticket.") } else { setSharingChoice("Il n'y pas d'informations patient partagées dans ce ticket.") } console.log('checkedValue', val) } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const updateContextWithCheckBox = (e: ChangeEvent<HTMLInputElement> ) => { handleCheck(e); updateContext(e); } const handleSaveUserInfo = (e: FormEvent, formData: IContactFormData | any) => { e.preventDefault(); saveForm(formData) console.log('context', formData) nextFormStep(); } return ( <> <form onSubmit={(e) => handleSaveUserInfo(e, formUserData)}> <label htmlFor='subjects'> Raisons </label> <div id="subjects"> <button type="button" id="subject" value='Détection de pathologie subtile' onClick={updateContext}> Détection de pathologie subtile </button> <button type="button" id="subject" value="Gain de temps" onClick={updateContext}> Gain de temps </button> <button type="button" id="subject" value="impact sur la prise en charge" onClick={updateContext}> impact sur la prise en charge </button> <textarea {...register("description")} id="description" name="description" defaultValue={infos[0].description} onChange={updateContext} /> <label htmlFor='sharePatientInfo'> Ne contient pas d'info patient </label> <input type="checkbox" placeholder="infoPatient " {...register("sharePatientInfo ")} id="sharePatientInfo" checked={val} value={sharingChoice} name="sharePatientInfo" onChange={updateContextWithCheckBox} /> <button type='submit'>Suivant</button> </div> </form> </> ) } export default ContactFormMain;
解决思路
1. 修复useState异步更新的逻辑错误
setVal(!val)依赖当前val的旧值,由于useState是异步更新,直接判断val会拿到未更新的旧状态。改用函数式更新并基于e.target.checked直接判断:
const handleCheck = (e: ChangeEvent<HTMLInputElement>): void => { const isChecked = e.target.checked; setVal(isChecked); setSharingChoice(isChecked ? "Des informations concernant le patient sont transmises dans ce ticket." : "Il n'y pas d'informations patient partagées dans ce ticket." ); }
2. 放弃手动维护表单状态,完全交给React Hook Form管理
同时使用React Hook Form和自定义useState会导致状态不一致,直接利用RHF的API管理表单数据:
const ContactFormMain: FunctionComponent<any> = ({ nextFormStep }) => { const { saveForm, infos } = useContext(ContactFormContext) as ContactFormDataType; // 初始化时传入默认值,让RHF接管状态 const { register, getValues, setValue } = useForm<IContactFormData>({ mode: "onBlur", defaultValues: infos[0] }); // 从默认值初始化复选框状态 const [val, setVal] = useState(infos[0].sharePatientInfo !== "Il n'y pas d'informations patient partagées dans ce ticket."); const handleCheck = (e: ChangeEvent<HTMLInputElement>): void => { const isChecked = e.target.checked; setVal(isChecked); // 直接用RHF的setValue更新字段 setValue("sharePatientInfo", isChecked ? "Des informations concernant le patient sont transmises dans ce ticket." : "Il n'y pas d'informations patient partagées dans ce ticket." ); } const handleSaveUserInfo = (e: FormEvent) => { e.preventDefault(); // 通过getValues获取最新表单数据 const formData = getValues(); saveForm(formData); nextFormStep(); } // 移除多余的updateContext和updateContextWithCheckBox }
3. 修复复选框的RHF注册问题
- 移除
register("sharePatientInfo ")中的空格,字段名要与表单数据的key一致 - 复选框的
onChange直接调用handleCheck即可,无需额外调用updateContext
4. 优化按钮组的逻辑
多个按钮共用同一个id="subject"不符合HTML规范,改用RHF的setValue直接更新字段:
<button type="button" onClick={() => setValue("subject", "Détection de pathologie subtile")}> Détection de pathologie subtile </button> <button type="button" onClick={() => setValue("subject", "Gain de temps")}> Gain de temps </button> <button type="button" onClick={() => setValue("subject", "impact sur la prise en charge")}> impact sur la prise en charge </button>
内容的提问来源于stack exchange,提问作者Ganzo
相关产品推荐
相关产品推荐

