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

如何用Zod验证首次无默认选中的单选按钮组表单?

Zod + React Hook Form 单选按钮初始未选中与验证解决方案

问题场景

我有一个使用zod进行验证的单选按钮表单,代码如下:

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

const FormSchema = z.object({
    options: z.enum(["option-0", "option-1", "option-2"], {
        required_error: "You must select an option",
    })
})

export default function Form() {
    const form = useForm<z.infer<typeof FormSchema>>({
        resolver: zodResolver(FormSchema),
        defaultValues: {
            options: "",
        },
    })

    const onSubmit = useCallback(async (data: z.infer<typeof FormSchema>) => {
        console.log(data)
    }, [])

    return (
            <form onSubmit={form.handleSubmit(onSubmit)}>
                {/* 单选按钮组 */}
            </form>
    )
}

这段代码无法正常运行,因为默认值""不在Zod枚举的可选值范围内。需要实现两个需求:

  • 首次渲染时无单选按钮被选中
  • 提交时通过Zod验证确保单选按钮值属于指定集合

解决方案

核心思路是:将字段初始值设为null(对应单选按钮未选中状态),同时调整Zod Schema,允许初始值为非枚举值,但强制提交时必须选择有效选项。

步骤1:调整Zod Schema

使用.nullable()允许字段初始值为null,再通过refine确保提交时字段不为null且属于枚举集合:

const FormSchema = z.object({
    options: z.enum(["option-0", "option-1", "option-2"])
        .nullable()
        .refine(val => val !== null, {
            message: "You must select an option",
        })
})

步骤2:配置React Hook Form

将默认值设为null,并设置验证模式为onSubmit(避免初始渲染就触发错误提示):

const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
    defaultValues: {
        options: null, // 初始未选中
    },
    mode: "onSubmit", // 仅提交时验证
})

步骤3:渲染单选按钮组

为每个枚举值生成单选按钮,绑定form.register:

<form onSubmit={form.handleSubmit(onSubmit)}>
    {["option-0", "option-1", "option-2"].map(option => (
        <div key={option}>
            <input
                type="radio"
                id={option}
                name="options"
                value={option}
                {...form.register("options")}
            />
            <label htmlFor={option}>{option}</label>
        </div>
    ))}
    {/* 错误提示 */}
    {form.formState.errors.options && (
        <p style={{ color: "red" }}>{form.formState.errors.options.message}</p>
    )}
    <button type="submit">提交</button>
</form>

效果说明

  • 首次渲染时,所有单选按钮都未被选中(因为表单初始值为null,无匹配的单选按钮value)
  • 提交时如果未选择任何选项,Zod会抛出"You must select an option"的错误
  • 选中任一有效选项后,表单可正常提交,且提交数据符合枚举要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:06:13