用钩子以形式响应派生状态

时间:2020-04-13 13:51:22

标签: reactjs typescript forms validation next.js

我一直在为我的React应用程序(使用Next.js)开发一个注册表单,而我确实在表单验证方面苦苦挣扎。我见过许多示例注册页面,它们都隐藏invalid消息,直到用户与输入进行交互为止。我尝试通过在输入字段为空时隐藏invalid消息来重新创建该消息,但是当用户键入某些内容然后将其擦除时,它不会显示任何内容。我想在用户尚未键入任何内容时隐藏invalid消息,然后再显示直到表单有效。我该如何在React中做到这一点?我的页面:

const SignUp: NextPage = () => {
  const firebase = useFirebase();
  const router = useRouter();

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [emailValid, setEmailValid] = useState({
    valid: true,
    message: "",
  });
  const [
    passwordValid,
    setPasswordValid,
  ] = useState({
    valid: true,
    message: "",
  });

  useEffect(() => {
    if (email === "") {
      setEmailValid({
        valid: true,
        message: "",
      });
      return;
    }
    const { valid, message } = validateInput(
      "email",
      email
    );

    setEmailValid({
      valid,
      message,
    });
  }, [email]);

  useEffect(() => {
    if (password === "") {
      setPasswordValid({
        valid: true,
        message: "",
      });
      return;
    }

    const { valid, message } = validateInput(
      "password",
      password
    );

    setPasswordValid({
      valid,
      message,
    });
  }, [password]);

  const handleSubmit = useCallback(
    (event: FormEvent<HTMLFormElement>) => {
      event.preventDefault();
      if (
        emailValid.valid === true &&
        passwordValid.valid === true &&
        email !== "" &&
        password !== ""
      ) {
        const error = firebase.createUser(
          email,
          password
        );
        if (error) {
          console.warn(error.code);
        } else {
          router.push("/");
        }
      } else {
        console.warn("Invalid user values");
      }
    },
    [
      email,
      emailValid.valid,
      firebase,
      password,
      passwordValid.valid,
      router,
    ]
  );

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="email">Email</label>
      <input
        value={email}
        onChange={(event): void =>
          setEmail(event.target.value)
        }
        id="email"
        placeholder="Email"
      />
      <p>{emailValid.message}</p>
      <label htmlFor="password">Password</label>
      <input
        value={password}
        onChange={(event): void =>
          setPassword(event.target.value)
        }
        id="password"
        placeholder="Password"
      />
      <p>{passwordValid.message}</p>
      <button type="submit">Submit</button>
    </form>
  );
};

export default SignUp;

我的验证功能如下:

type InputType = "email" | "password";

function validateInput(
  inputType: InputType,
  inputValue: string
): { valid: boolean; message: string } {
  switch (inputType) {
    case "email":
      if (!inputValue.includes("@")) {
        return {
          valid: false,
          message:
            "The email field must be a valid email",
        };
      } else {
        return {
          valid: true,
          message: "",
        };
      }

    case "password":
      if (inputValue.length < 8) {
        return {
          valid: false,
          message:
            "The password field must be at least 8 characters",
        };
      } else if (
        inputValue.toUpperCase() === inputValue
      ) {
        return {
          valid: false,
          message:
            "The password must contain an lowercase character",
        };
      } else if (
        inputValue.toLocaleLowerCase() ===
        inputValue
      ) {
        return {
          valid: false,
          message:
            "The password must contain an uppercase character",
        };
      } else if (
        /\d/.test(inputValue) === false
      ) {
        return {
          valid: false,
          message:
            "The password must contain a number",
        };
      } else {
        return {
          valid: true,
          message: "",
        };
      }

    default:
      return {
        valid: false,
        message: "Input type is invalid",
      };
  }
}

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

这可能不是您正在寻找的确切解决方案,但这就是我在代码中进行验证的方式。

const [name, setName] = React.useState("")
const [error, setError] = React.useState(false)

const handleClick = () => {
/// Your error conditions here. Match them with if or switch.
/// If form is invalid, setError to true.
setError(true)
}

<form>
<input type="text" value={name} onChange={e => setName(e.target.value)} />
{error && name.length<1 ? <span>Name is required</span>}
<button onClick={handleClick}>Click</button>
</form>