如何将 React hook 表单与自定义输入组件(使用 Zod)一起使用?

问题描述 投票:0回答:1
                <StarRatingInput
                  rating={rating}
                  setRating={(newValue: string) => {
                    setRating(newValue);
                    (
                      document.getElementById("rating") as HTMLInputElement
                    ).value = newValue;
                    console.log("new", newValue);
                  }}
                />
                <input hidden id="rating" type="text" {...register("rating")}/>

在上面的代码中,StarRatingInput 是一个组件,它并不是真正的输入元素,而是被用作一个输入元素。由于我无法在该组件内注册挂钩表单,因此我在其下方创建了一个新的隐藏

input
标签,尝试注册它。根据上面的代码,当
rating
状态改变时,
input
标签的值也会改变。但我无法对
rating
执行验证。

我的评级验证如下

  rating: z.string().refine(
    (value: string) => {
      console.log(value);
      const ratings = ["1", "2", "3", "4", "5"];
      return ratings.includes(value);
    },
    { message: "Please select valid rating stars" },
  ),

问题在于,精炼回调函数内的值始终为空字符串。 我可以确认

input
标签的值正在变化,但无论怎样
value
参数始终为空字符串。

我还尝试将

input
标签更改为受控组件,但它也不起作用
<input value={rating} id="rating" type="text" {...register("rating")}/>

StarRatingInput.tsx 的实现

function StarRatingInput({
  rating,
  setRating,
}: {
  rating: string;
  setRating: (newValue: string) => void;
}) {
  return (
    <div>
      {[1, 2, 3, 4, 5].map((star) => {
        return (
          <span
            key={star}
            className="start"
            style={{
              cursor: "pointer",
              color: parseInt(rating) >= star ? "gold" : "gray",
              fontSize: `35px`,
            }}
            onClick={() => {
              setRating(star.toString());
            }}
          >
            {" "}
            ★{" "}
          </span>
        );
      })}
    </div>
  );
}

export default StarRatingInput;
reactjs typescript react-hook-form zod
1个回答
0
投票

不建议采用这种方法。你几乎永远不会想直接改变react中的DOM。

React hook 表单提供了与非

<input>
元素交互的其他方式。

getValues
setValue
函数。

例如:

  const { getValues, setValue, watch, register } = useForm({
    defaultValues: { name: '', isCool: false }
  })

现在您可以访问

isCool
表单状态来呈现该值:

{ getValues('isCool') ? 'Cool' : 'Not Cool' }

并且可以通过调用

setValue
来设置:

    <button onClick={() => setValue('isCool', true)}>Cool</button>
    <button onClick={() => setValue('isCool', false)}>Not Cool</button>

但一个问题是,反应钩子表单假设表单状态值不需要重新渲染页面。因此,添加对

watch
的调用会告诉它监视该字段上的更改并重新渲染。

  useEffect(() => {
    watch('isCool') // Ensures a re-render when `isCool` is changed.
  }, [])

请参阅游乐场,其中包含类型安全但不可运行的示例。

© www.soinside.com 2019 - 2024. All rights reserved.