You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:05:45