如何在React Hook Form客户端组件中从数据库预取并设置默认值?
解决shadcn Select组件异步设置react-hook-form默认值的问题
要实现从数据库异步预取默认值并同步到表单,你可以按以下步骤调整代码:
- 新增异步数据获取逻辑:用
useEffect发起请求拉取数据库中的默认值 - 手动更新表单字段:数据返回后调用react-hook-form的
setValue方法设置对应字段值 - 处理加载状态:避免在数据未返回时渲染未初始化的表单
修改后的完整代码示例:
"use client" import { useEffect, useState } from "react" import Link from "next/link" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { z } from "zod" import { Button } from "@/components/ui/button" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { toast } from "@/components/ui/use-toast" const FormSchema = z.object({ email: z .string({ required_error: "请选择一个要显示的邮箱。", }) .email(), }) export function SelectForm() { const [isLoading, setIsLoading] = useState(true) const form = useForm<z.infer<typeof FormSchema>>({ resolver: zodResolver(FormSchema), // 先设置空默认值,后续异步更新 defaultValues: { email: "" } }) // 模拟从数据库异步获取默认值 useEffect(() => { const fetchDefaultEmail = async () => { try { // 替换为你实际的接口请求 const res = await fetch("/api/user/default-email") const data = await res.json() // 同步表单字段值 form.setValue("email", data.defaultEmail) } catch (err) { console.error("获取默认邮箱失败:", err) } finally { setIsLoading(false) } } fetchDefaultEmail() }, [form.setValue]) function onSubmit(data: z.infer<typeof FormSchema>) { toast({ title: "你提交了以下内容:", description: ( <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4"> <code className="text-white">{JSON.stringify(data, null, 2)}</code> </pre> ), }) } if (isLoading) { return <div>加载中...</div> } return ( <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6"> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem> <FormLabel>邮箱</FormLabel> <Select onValueChange={field.onChange} defaultValue={field.value}> <FormControl> <SelectTrigger> <SelectValue placeholder="选择一个已验证的邮箱进行显示" /> </SelectTrigger> </FormControl> <SelectContent> <SelectItem value="m@example.com">m@example.com</SelectItem> <SelectItem value="m@google.com">m@google.com</SelectItem> <SelectItem value="m@support.com">m@support.com</SelectItem> </SelectContent> </Select> <FormDescription> 你可以在你的{" "} <Link href="/examples/forms">邮箱设置</Link>中管理邮箱地址。 </FormDescription> <FormMessage /> </FormItem> )} /> <Button type="submit">提交</Button> </form> </Form> ) }
核心说明:
- 异步获取+setValue同步:组件挂载后发起请求,数据返回后用
setValue直接更新表单字段,这是异步设置默认值的关键 - 初始空值+加载状态:先给字段设置空值避免初始化时触发校验错误,加载状态提升用户体验
- 依赖项管理:把
form.setValue加入useEffect依赖,确保更新逻辑的正确性
内容的提问来源于stack exchange,提问作者Marc Willhaus
相关产品推荐
相关产品推荐

