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

react-hook-form提交时state绑定输入值无法检测报错如何解决

错误原因

NaN警告

  • 初始化的price状态值为空字符串,当用户清空输入框或输入非数字内容时,parseInt(ev.target.value)会返回NaN,将NaN赋值给输入框的value属性就会触发该警告。

表单取不到voucherPrice值

  • 你同时使用了自定义state管理输入值和react-hook-form管控表单,但仅将register返回的引用绑定到了输入框的innerRef,react-hook-form没有收到值更新的通知:你自定义的onChange事件仅更新了本地的price状态,没有同步给表单,因此提交时会触发必填校验错误。

修复方案

  1. 从useForm中导出setValue方法,用于将本地状态同步到表单
  2. 新增useEffect监听price变化,自动同步到表单,不需要在每个值变更的地方重复写同步逻辑
  3. 优化数字转换逻辑,避免返回NaN

完整修改后代码

import React from "react";
import { useStylesPriceSelection } from "../../styles/stepStyles";
import clsx from "clsx";
import { Input } from "reactstrap";
import { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import Button from "@mui/material/Button";

const schema = yup
  .object({
    voucherPrice: yup.number().positive().required(),
  })
  .required();

function PriceSelection(props) {
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors },
  } = useForm({
    resolver: yupResolver(schema),
  });
  const onSubmit = (data) => console.log(data);

  const classes = useStylesPriceSelection();
  const [selected, setSelected] = useState(false);
  const [price, setPrice] = useState("");

  // 监听price变化,自动同步到react-hook-form
  useEffect(() => {
    setValue("voucherPrice", price, { shouldValidate: true });
  }, [price, setValue]);

  const handleSelectedBox = (ev) => {
    console.log("", price);
    setSelected(ev.target.getAttribute("data-boxprice"));
    const priceVal = parseInt(ev.target.getAttribute("data-price"));
    setPrice(isNaN(priceVal) ? "" : priceVal);
  };

  const handlePriceInputChange = (ev) => {
    console.log("change", price);
    const inputVal = ev.target.value;
    const priceVal = inputVal ? parseInt(inputVal) : "";
    setPrice(isNaN(priceVal) ? "" : priceVal);
  };

  const priceBox1 = 25;
  const priceBox2 = 50;
  const priceBox3 = 75;
  const priceBox4 = 100;

  return (
    <div>
      <section className={classes.priceBoxWrap}>
        <div
          data-boxprice="1"
          data-price={`${priceBox1}`}
          onClick={(ev) => handleSelectedBox(ev)}
          className={clsx(
            classes.priceBox,
            ((selected === "1" && price === priceBox1) ||
              price === priceBox1) &&
              classes.priceBoxSelected
          )}
        >
          {`${priceBox1}€`}
        </div>

        <div
          data-boxprice="2"
          data-price={`${priceBox2}`}
          onClick={(ev) => handleSelectedBox(ev)}
          className={clsx(
            classes.priceBox,
            ((selected === "2" && price === priceBox2) ||
              price === priceBox2) &&
              classes.priceBoxSelected
          )}
        >
          {`${priceBox2}€`}
        </div>
      </section>

      <section className={classes.priceBoxWrap}>
        <div
          data-boxprice="3"
          data-price={`${priceBox3}`}
          onClick={(ev) => handleSelectedBox(ev)}
          className={clsx(
            classes.priceBox,
            ((selected === "3" && price === priceBox3) ||
              price === priceBox3) &&
              classes.priceBoxSelected
          )}
        >
          {`${priceBox3}€`}
        </div>

        <div
          data-boxprice="4"
          data-price={`${priceBox4}`}
          onClick={(ev) => handleSelectedBox(ev)}
          className={clsx(
            classes.priceBox,
            ((selected === "4" && price === priceBox4) ||
              price === priceBox4) &&
              classes.priceBoxSelected
          )}
        >
          {`${priceBox4}€`}
        </div>
      </section>
      <form onSubmit={handleSubmit(onSubmit)}>
        <Input
          onChange={handlePriceInputChange}
          type="number"
          value={price}
          innerRef={register("voucherPrice", { required: true })}
        ></Input>
        <p>{errors.voucherPrice?.message}</p>

        <Button
          variant="contained"
          sx={{ mt: 1, mr: 1 }}
          type="submit"
        >
          Continue
        </Button>
      </form>
    </div>
  );
}

export default PriceSelection;

内容的提问来源于stack exchange,提问作者Gotey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 04:15:06