You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
  );
};

关键修改点

  1. 邮箱输入框状态调整:将disabled={isLoading || isEmailSubmitted}改为readOnly={isEmailSubmitted} disabled={isLoading},避免字段被注销,同时限制提交后不可修改。
  2. 自动聚焦优化:给邮箱输入框添加autoFocus={!isEmailSubmitted},确保初始加载时聚焦邮箱,提交后不重复聚焦。
  3. 提交按钮禁用:给提交按钮添加disabled={isLoading},避免重复提交。

内容的提问来源于stack exchange,提问作者Nagy Dániel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:50:01