如何在Shadcn Form+Zod中通过onChange获取值并实现密码强度条
解决React Hook Form + Zod表单中密码强度条不更新的问题
核心方案:使用React Hook Form的watch方法
React Hook Form内置的watch API专门用于监听表单字段的实时变化,相比手动调用getValues配合useEffect更可靠,还无需额外维护状态。
修改步骤:
- 移除原有的
useState和useEffect代码段:
// 删除这部分代码 const [pass, setPass] = useState<string>(""); useEffect(() => { setPass(form.getValues("password")); }, [form]);
- 通过
watch获取实时密码值:
const password = form.watch("password");
- 直接将
password传入密码强度组件:
<PasswordStrengthBar password={password} />
完整修改后的代码:
"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import { useForm } from "react-hook-form"; import { useContext } from "react"; import NotificationContext from "@/lib/context/notification-context"; import defaultNotification from "@/lib/locale/default-notification"; import PasswordStrengthBar from "react-password-strength-bar"; import { authFormSchema } from "@/lib/formSchema"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import SubmitButton from "../ui/custom-ui/submit-btn"; export default function AuthForm() { const notifCtx = useContext(NotificationContext); const form = useForm<z.infer<typeof authFormSchema>>({ resolver: zodResolver(authFormSchema), defaultValues: { email: "", password: "" } }); const isLoading = form.formState.isSubmitting; // 监听密码字段的实时变化 const password = form.watch("password"); async function onSubmit(values: z.infer<typeof authFormSchema>) { notifCtx.setNotification(defaultNotification.pending); const res = await fetch("/api/auth/signup", { method: "POST", body: JSON.stringify({ ...values }) }); const { err, msg } = await res.json(); notifCtx.setNotification(defaultNotification[err ? "error" : "success"](msg)); !err && form.reset(); return; } return ( <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-2"> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem> <FormLabel>Email</FormLabel> <FormControl> <Input placeholder="john@doe.com" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="password" render={({ field }) => ( <FormItem> <FormLabel className="">Password</FormLabel> <FormControl> <Input placeholder="password123" type="password" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> {/* 传入实时监听的密码值 */} <PasswordStrengthBar password={password} /> <div className=""> <SubmitButton className="w-full my-4 dark:bg-white dark:hover:bg-primary dark:text-black dark:hover:text-white" isLoading={isLoading} text="Sign up" /> </div> </form> </Form> ); }
备选方案:扩展Input的onChange事件
如果需要手动维护状态,也可以在FormField的渲染逻辑中扩展field.onChange,同时保留React Hook Form的表单逻辑与自定义状态同步:
<FormField control={form.control} name="password" render={({ field }) => ( <FormItem> <FormLabel className="">Password</FormLabel> <FormControl> <Input placeholder="password123" type="password" {...field} onChange={(e) => { // 优先执行原表单的onChange逻辑 field.onChange(e); // 同步更新自定义状态 setPass(e.target.value); }} /> </FormControl> <FormMessage /> </FormItem> )} />
内容的提问来源于stack exchange,提问作者eyyMinda
相关产品推荐
相关产品推荐

