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

React Hook Form结合Zod使用自定义评分组件时验证失效问题

解决React Hook Form结合Zod验证自定义星级组件的问题

你遇到的核心问题是:手动修改隐藏input的value不会触发React Hook Form(RHF)的状态更新——RHF依赖表单元素的change事件跟踪值变化,直接操作DOM属性无法让RHF感知到值的更新,因此Zod验证时始终拿到空字符串。

以下是两种可行的解决方案,优先推荐第一种标准实现方式:

方案1:使用React Hook Form的Controller组件(推荐)

Controller是RHF官方提供的、专门用于整合非原生表单组件的工具,无需手动维护隐藏input,直接将自定义组件与RHF的表单状态绑定。

修改父组件代码

import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import StarRatingInput from "./StarRatingInput";

// Zod验证规则
const FormSchema = z.object({
  rating: z.string().refine(
    (value) => {
      const validRatings = ["1", "2", "3", "4", "5"];
      return validRatings.includes(value);
    },
    { message: "请选择有效的星级" },
  ),
});

type FormValues = z.infer<typeof FormSchema>;

export default function RatingForm() {
  const { control, handleSubmit, formState: { errors } } = useForm<FormValues>({
    resolver: zodResolver(FormSchema),
    defaultValues: { rating: "" }
  });

  const onSubmit = (data: FormValues) => {
    console.log("提交数据:", data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="rating"
        control={control}
        render={({ field: { onChange, value } }) => (
          <StarRatingInput
            rating={value}
            setRating={onChange} // 直接将RHF的状态更新方法传给组件
          />
        )}
      />
      {errors.rating && <p style={{ color: "red" }}>{errors.rating.message}</p>}
      <button type="submit">提交</button>
    </form>
  );
}

StarRatingInput组件无需修改

保持你原有的组件实现即可,它只需要负责渲染星级和触发值变更回调。

方案2:手动触发隐藏input的change事件(仅作参考)

如果不想使用Controller,需要在修改隐藏input的value后,手动触发change事件,让RHF感知到值的变化:

<StarRatingInput
  rating={rating}
  setRating={(newValue: string) => {
    setRating(newValue);
    const ratingInput = document.getElementById("rating") as HTMLInputElement;
    ratingInput.value = newValue;
    // 手动触发change事件,通知RHF更新状态
    ratingInput.dispatchEvent(new Event("change"));
  }}
/>
<input hidden id="rating" type="text" {...register("rating")}/>

这种方式需要手动操作DOM,容易引发状态不同步问题,仅适合临时兼容场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 07:44:55