编辑页从数据库动态取数时Checkbox勾选状态异常求助
问题:切换会议类型后切回,Checkbox未勾选但数据仍存在
我做了一个编辑页面,从数据库获取数据,根据meeting_type_option的值渲染对应字段。初始加载时Checkbox能正确勾选,但切换到其他选项后清空了相关数据,再切回原选项时,Checkbox没勾选,但对应的数据还在。
代码实现
数据获取与表单初始化
const appoinment = useQuery({ queryKey: ['appointment', 'data', 'history', id], queryFn: () => fetch(`/api/single-sched/${id}`).then((res) => res.json()) }) const { data, isLoading, error } = appoinment; const form = useForm<CreateAppointmentSchemaType>({ resolver: zodResolver(CreateAppointmentSchema), });
监听会议类型并渲染字段
let watchEvent = form.watch("meeting_type_option");
会议类型选择器
<FormField control={form.control} name="meeting_type_option" defaultValue={data?.meeting_type_option} render={({ field }) => ( <FormItem className="w-full"> <FormLabel>Type of Service</FormLabel> <Select onValueChange={(value) => handleMeetingTypeChange(value) } defaultValue={field.value} > <FormControl> <SelectTrigger> <SelectValue placeholder="Select a meeting type" /> </SelectTrigger> </FormControl> <SelectContent> <SelectItem value="meeting"> Zoom Meeting </SelectItem> <SelectItem value="webinar"> Zoom Webinar </SelectItem> <SelectItem value="hybrid">Hybrid</SelectItem> <SelectItem value="documentation"> Documentation </SelectItem> <SelectItem value="training"> Training </SelectItem> </SelectContent> </Select> <FormMessage /> </FormItem> )} /> {watchEvent === "meeting" && ( <> // 与webinar类似的表单字段 </> )} {watchEvent === "webinar" && ( <> <FormField control={form.control} name="meeting_type_service" render={() => ( <FormItem> {zoomWebinarChoice.map((item) => ( <FormField key={item.id} control={form.control} name="meeting_type_service" render={({ field }) => { return ( <FormItem key={item.id} className="flex flex-row items-start space-x-3 space-y-0" > <FormControl> <Checkbox checked={field.value?.includes(item.id)} onCheckedChange={(checked) => { return checked ? field.onChange([ ...field.value, item.id, ]) : field.onChange( field.value?.filter( (value) => value !== item.id ) ); }} /> </FormControl> <FormLabel className="font-normal"> {item.label} </FormLabel> </FormItem> ); }} /> ))} <FormMessage /> </FormItem> )} /> </> )}
Checkbox配置项
export const zoomMeetingChoice = [ { id: 'meeting_attendees', label: 'Attendees can open their camera', }, { id: 'meeting_waiting', label: 'Waiting Room', }, { id: 'meeting_breakout', label: "Breakout Room" }, { id: 'meeting_poll', label: 'Poll' }, { id: 'meeting_recording', label: 'Recording' }, { id: 'meeting_livestream', label: 'Livestreaming' }, { id: 'meeting_hybrid', label: "Hybrid" } ]
问题根源
- 表单初始化未全局设置
defaultValues,仅给单个字段加defaultValue,导致切回原类型时无法从原始数据恢复字段值 - 切换会议类型的函数仅清空数据,未在切回时重新注入对应类型的原始数据
- 嵌套
FormField导致Checkbox状态与表单字段值不同步
解决方法
1. 全局初始化表单默认值
把数据库返回的data作为表单全局默认值,移除单个FormField上的defaultValue:
const form = useForm<CreateAppointmentSchemaType>({ resolver: zodResolver(CreateAppointmentSchema), defaultValues: data ?? {}, });
2. 优化会议类型切换逻辑
切换时根据目标类型恢复对应字段的原始数据,非目标类型则清空:
const handleMeetingTypeChange = (value: string) => { form.setValue('meeting_type_option', value); if (value === 'webinar') { form.setValue('meeting_type_service', data?.meeting_type_service ?? []); } else if (value === 'meeting') { // 假设meeting对应字段为meeting_type_service_meeting,根据实际调整 form.setValue('meeting_type_service_meeting', data?.meeting_type_service_meeting ?? []); } else { form.setValue('meeting_type_service', []); form.setValue('meeting_type_service_meeting', []); } };
建议给不同会议类型的服务选项设置独立字段,避免数据冲突
3. 简化Checkbox渲染结构
去掉嵌套的FormField,用单个FormField包裹所有Checkbox,确保状态与表单字段完全同步:
{watchEvent === "webinar" && ( <FormField control={form.control} name="meeting_type_service" render={({ field }) => ( <FormItem> {zoomWebinarChoice.map((item) => ( <FormItem key={item.id} className="flex flex-row items-start space-x-3 space-y-0" > <FormControl> <Checkbox checked={field.value?.includes(item.id)} onCheckedChange={(checked) => { const newValue = checked ? [...(field.value || []), item.id] : field.value?.filter(id => id !== item.id) || []; field.onChange(newValue); }} /> </FormControl> <FormLabel className="font-normal"> {item.label} </FormLabel> </FormItem> ))} <FormMessage /> </FormItem> )} /> )}
4. 监听数据更新同步表单
如果数据库数据可能在页面加载后更新,添加监听同步表单:
useEffect(() => { if (data) { form.reset(data); } }, [data, form]);
内容的提问来源于stack exchange,提问作者Stykgwar
相关产品推荐
相关产品推荐

