Day11-React 表单验证篇-不使用 hook 或第三方函式库

React 的表单验证篇总共会三篇,这篇我们会自己手刻一个验证输入值是否合法的表单,而在後面两篇文章,我将会介绍使用 custom hook 及有名的第三方函式库去实作表单验证。

这篇文章不会注重 CSS 的样式,有兴趣的读者在跟着步骤时可以自行加入。

1. 简单做一个表单出来

const SimpleForm = () => {
  return (
    <form>
      <label htmlFor="name">Your Name</label>
      <input type="text" id="name" />
      <label htmlFor="email">Your E-Mail</label>
      <input type="email" id="email" />
      <button>Submit</button>
    </form>
  );
};

2. 将表单栏位会用到的 state、事件处理都加入

const emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;

const SimpleForm = () => {
  const [name, setName] = useState("");
  const [nameTouched, setNameTouched] = useState(false);
  const [email, setEmail] = useState("");
  const [emailTouched, setEmailTouched] = useState(false);

  const nameIsValid = name.trim() !== "";
  const emailIsValid = emailRule.test(email);

  const onChangeName = (e) => setName(e.target.value);
  const onBlurName = () => setNameTouched(true);
  const onChangeEmail = (e) => setEmail(e.target.value);
  const onBlurEmail = () => setEmailTouched(true);

  return (
    <form>
      <label htmlFor="name">Your Name</label>
      <input
        type="text"
        id="name"
        onChange={onChangeName}
        onBlur={onBlurName}
        value={name}
      />
      <label htmlFor="email">Your E-Mail</label>
      <input
        type="email"
        id="email"
        onChange={onChangeEmail}
        onBlur={onBlurEmail}
        value={email}
      />
      <button>Submit</button>
    </form>
  );
};

3. 接着为送出表单的按钮绑定事件

const SimpleForm = () => {
  const [name, setName] = useState("");
  const [nameTouched, setNameTouched] = useState(false);
  const [email, setEmail] = useState("");
  const [emailTouched, setEmailTouched] = useState(false);

  const nameIsValid = name.trim() !== "";
  const emailIsValid = emailRule.test(email);

  const onChangeName = (e) => setName(e.target.value);
  const onBlurName = () => setNameTouched(true);
  const onChangeEmail = (e) => setEmail(e.target.value);
  const onBlurEmail = () => setEmailTouched(true);

  const onFormSubmit = (e) => {
    e.preventDefault();

    if (!nameIsValid) setNameTouched(true);
    if (!emailIsValid) setEmailTouched(true);
    if (!nameIsValid || !emailIsValid) return;

    console.log("submit success!");
    console.log(name, email);

    // reset
    setName("");
    setNameTouched(false);
    setEmail("");
    setEmailTouched(false);
  };

  return (
    <form onSubmit={onFormSubmit}>
      <label htmlFor="name">Your Name</label>
      <input
        type="text"
        id="name"
        onChange={onChangeName}
        onBlur={onBlurName}
        value={name}
      />
      <label htmlFor="email">Your E-Mail</label>
      <input
        type="email"
        id="email"
        onChange={onChangeEmail}
        onBlur={onBlurEmail}
        value={email}
      />
      <button disabled={!nameIsValid || !emailIsValid}>Submit</button>
    </form>
  );
};

4. 最後加上错误的提示讯息

先加上一小段 CSS

.invalid {
  border: 1px solid red;
}

.error-text {
  color: red;
}

主程序的部分

const SimpleForm = () => {
  const [name, setName] = useState("");
  const [nameTouched, setNameTouched] = useState(false);
  const [email, setEmail] = useState("");
  const [emailTouched, setEmailTouched] = useState(false);

  const nameIsValid = name.trim() !== "";
  const emailIsValid = emailRule.test(email);

  const onChangeName = (e) => setName(e.target.value);
  const onBlurName = () => setNameTouched(true);
  const onChangeEmail = (e) => setEmail(e.target.value);
  const onBlurEmail = () => setEmailTouched(true);

  const onFormSubmit = (e) => {
    e.preventDefault();

    if (!nameIsValid) setNameTouched(true);
    if (!emailIsValid) setEmailTouched(true);
    if (!nameIsValid || !emailIsValid) return;

    console.log("submit success!");
    console.log(name, email);

    // reset
    setName("");
    setNameTouched(false);
    setEmail("");
    setEmailTouched(false);
  };

  const nameInputClasses = !nameIsValid && nameTouched ? "invalid" : "";
  const emailInputClasses = !emailIsValid && emailTouched ? "invalid" : "";

  return (
    <form onSubmit={onFormSubmit}>
      <label htmlFor="name">Your Name</label>
      <input
        type="text"
        id="name"
        onChange={onChangeName}
        onBlur={onBlurName}
        value={name}
        className={nameInputClasses}
      />
      {!nameIsValid && nameTouched && (
        <p className="error-text">Name must not be empty.</p>
      )}
      <label htmlFor="email">Your E-Mail</label>
      <input
        type="email"
        id="email"
        onChange={onChangeEmail}
        onBlur={onBlurEmail}
        value={email}
        className={emailInputClasses}
      />
      {!emailIsValid && emailTouched && (
        <p className="error-text">Please enter a valid email.</p>
      )}
      <button disabled={!nameIsValid || !emailIsValid}>Submit</button>
    </form>
  );
};

程序码范例(codesandbox)

透过以上步骤,就可以建立出简单的表单验证,有错误的提示文字外也有输入框边框变红色的警告提示,不过当表格要填入的栏位变多就会变得复杂。

因此下一篇将用 custom hook 去进行表单验证,将一些栏位输入的相关逻辑抽取出来。


<<:  Angular 深入浅出三十天:表单与测试 Day10 - Template Driven Forms 实作 - 动态表单初体验

>>:  Day10-元件沟通传递(part2)

Outlook 的 PST 档不见导致无法开启要如何修复

概述: 本教学提供了两种非常简单的Outlook修复方法,解决了Outlook PST文件找不到导致...

[DAY12]跟 Vue.js 认识的30天 - Vue 模组资料传递(`props`)

props 的命名及使用 HTML attribute 是大小写不敏感的,所以必须要注意 prop ...

Day10-119. Pascal's Triangle II

今日题目:119. Pascal's Triangle II Given an integer ro...

Day 7 Compose UI Image Layout

今年的疫情蛮严重的,希望大家都过得安好,希望疫情快点过去,能回到一些线下技术聚会的时光~ 今天要开始...

Day6 Data types, Variables, and Operators (Ⅱ)

Integers(整数) ●最常使用的是integer type是int ●如果数字超出type的可...