切换RadioField时清空关联InputField的实现方案(shadcn+react-hook-form)
解决React Hook Form切换单选框后额外字段仍保留的问题
问题根源
React Hook Form会持久化所有已注册字段的值,哪怕对应的输入组件通过条件渲染被隐藏。所以当你从yes切换到no时,之前填写的dryRunDate、dryRunStart、dryRunEnd仍会留在表单提交数据中。
具体解决方案
方案1:监听单选框变化,清除额外字段值
在RadioGroup的onValueChange回调里,当切换到no时,主动清空相关字段的值。这种方式直接且直观,能确保提交数据里不会包含不需要的字段内容。
修改RadioGroup部分代码:
<RadioGroup onValueChange={(value) => { field.onChange(value); // 切换到no时清空额外字段 if (value === 'no') { form.setValue('dryRunDate', ''); form.setValue('dryRunStart', ''); form.setValue('dryRunEnd', ''); } }} defaultValue={field.value} className="flex flex-col space-y-1" >
方案2:通过Zod Schema做条件约束+提交数据过滤
先在Schema里设置规则:当type为yes时,额外字段必填;当type为no时,这些字段可选。提交时再手动过滤掉不需要的字段,彻底从提交数据里移除。
1. 修改Zod Schema
import { z } from 'zod'; const FormSchema = z.object({ type: z.enum(['yes', 'no']), dryRunDate: z.string().optional(), dryRunStart: z.string().optional(), dryRunEnd: z.string().optional(), }).refine((data) => { // type为yes时,必须填写所有额外字段 if (data.type === 'yes') { return data.dryRunDate && data.dryRunStart && data.dryRunEnd; } return true; }, { message: '请完善dryRun相关字段', path: ['dryRunDate'], });
2. 处理提交数据
const onSubmit = (data: z.infer<typeof FormSchema>) => { // 过滤掉type为no时的额外字段 const submitData = data.type === 'no' ? { type: data.type } : data; // 使用submitData进行后续提交操作 };
方案3:注销字段(不推荐)
可以用form.unregister在切换到no时注销额外字段,但后续切回yes时需要重新注册,容易引发组件状态异常,因此更推荐前两种方案。
完整优化代码示例
结合方案1,同时修正原代码里的标签重复问题:
const form = useForm<z.infer<typeof FormSchema>>({ resolver: zodResolver(FormSchema), defaultValues: { type: 'no', dryRunDate: '', dryRunStart: '', dryRunEnd: '', } }); <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6"> <FormField control={form.control} name="type" render={({ field }) => ( <FormItem className="space-y-3"> <FormLabel>Optional;</FormLabel> <FormControl> <RadioGroup onValueChange={(value) => { field.onChange(value); if (value === 'no') { form.setValue('dryRunDate', ''); form.setValue('dryRunStart', ''); form.setValue('dryRunEnd', ''); } }} defaultValue={field.value} className="flex flex-col space-y-1" > <FormItem className="flex items-center space-x-3 space-y-0"> <FormControl> <RadioGroupItem value="yes" /> </FormControl> <FormLabel className="font-normal">yes</FormLabel> </FormItem> <FormItem className="flex items-center space-x-3 space-y-0"> <FormControl> <RadioGroupItem value="no" /> </FormControl> <FormLabel className="font-normal">no</FormLabel> </FormItem> {/* 直接用field.value判断,无需额外状态变量 */} {field.value === "yes" && ( <> <FormField control={form.control} name="dryRunDate" render={({ field }) => ( <FormItem> <FormLabel>dryRunDate</FormLabel> <FormControl> <Input type="text" placeholder="date" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="dryRunStart" render={({ field }) => ( <FormItem> <FormLabel>dryRunStart</FormLabel> <FormControl> <Input type="text" placeholder="start time" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="dryRunEnd" render={({ field }) => ( <FormItem> <FormLabel>dryRunEnd</FormLabel> <FormControl> <Input type="text" placeholder="end time" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> </> )} </RadioGroup> </FormControl> <FormMessage /> </FormItem> )} /> <Button type="submit">Submit</Button> </form> </Form>
内容的提问来源于stack exchange,提问作者Stykgwar
相关产品推荐
相关产品推荐

