React Hook Form两步表单提交后邮箱字段重置问题求助
问题:两步登录表单提交时邮箱值丢失
我使用react-hook-form实现了一个两步登录表单,流程为:先输入邮箱并提交,再输入密码完成登录。但第一步提交邮箱后,邮箱字段的值会被重置为undefined,导致最终提交时缺少邮箱信息,无法完成登录流程。
问题原因
当邮箱输入框被设置为disabled={isLoading || isEmailSubmitted}后,即使配置了shouldUnregister: false,react-hook-form依然会自动注销该字段的注册信息,导致后续无法读取到邮箱值。
解决方案
需要保留邮箱字段的注册状态,同时让它在提交后不可编辑。可以将disabled替换为readOnly(仅在邮箱提交后生效),这样既限制用户修改,又能维持字段的注册状态,保证最终提交时能获取到邮箱值。
修改后的代码
import { useState, useCallback } from "react"; import { useForm, zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; export default function App() { const [inProgress, setInProgress] = useState(false); const handleSubmit = (email: string, password: string) => { console.log("SimplifiedSignInForTesting submitted:", { email, password }); setInProgress(true); setTimeout(() => { setInProgress(false); }, 1500); }; return <SignIn submit={handleSubmit} inProgress={inProgress} />; } interface SignInProps { submit: (email: string, password: string) => void; inProgress: boolean; } export const SignIn = ({ submit, inProgress }: SignInProps) => { const [isEmailSubmitted, setIsEmailSubmitted] = useState(false); const schema = z.object({ email: z.string().email("请输入有效的邮箱地址"), password: z.string().min(6, "密码长度不能少于6位"), }); type SignInFormData = z.infer<typeof schema>; const { register, handleSubmit, setFocus, formState: { errors, isSubmitting }, } = useForm<SignInFormData>({ resolver: zodResolver(schema), shouldUnregister: false, defaultValues: { email: "", password: "", }, }); const onSubmitInternal = useCallback( async (data: SignInFormData) => { const { email, password } = data; if (!isEmailSubmitted) { setIsEmailSubmitted(true); setTimeout(() => setFocus("password"), 0); return; } submit(email, password); }, [isEmailSubmitted, submit, setFocus] ); const isLoading = inProgress || isSubmitting; const emailErrorMessage = errors.email?.message; return ( <form onSubmit={handleSubmit(onSubmitInternal)} noValidate> <input tabIndex={0} autoFocus={!isEmailSubmitted} aria-label="email" type="email" // 替换disabled为readOnly,仅在邮箱提交后只读,禁用仅在加载时生效 readOnly={isEmailSubmitted} disabled={isLoading} {...register("email")} /> {emailErrorMessage && <span style={{ color: "red" }}>{emailErrorMessage}</span>} <input aria-label="password" type="password" autoComplete="current-password" style={{ display: isEmailSubmitted ? "initial" : "none" }} disabled={isLoading} tabIndex={isEmailSubmitted ? 0 : -1} {...register("password")} /> <input tabIndex={0} type="submit" disabled={isLoading} aria-label={isEmailSubmitted ? "登录" : "继续"} /> </form> ); };
关键修改点
- 邮箱输入框状态调整:将
disabled={isLoading || isEmailSubmitted}改为readOnly={isEmailSubmitted} disabled={isLoading},避免字段被注销,同时限制提交后不可修改。 - 自动聚焦优化:给邮箱输入框添加
autoFocus={!isEmailSubmitted},确保初始加载时聚焦邮箱,提交后不重复聚焦。 - 提交按钮禁用:给提交按钮添加
disabled={isLoading},避免重复提交。
内容的提问来源于stack exchange,提问作者Nagy Dániel
相关产品推荐
相关产品推荐

