iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Modern Web

用30天更加認識 React.js 這個好朋友系列 第 11

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 去進行表單驗證,將一些欄位輸入的相關邏輯抽取出來。


上一篇
Day10-React Hook 篇-打造自己的 Hook:Custom Hook
下一篇
Day12-React 表單驗證篇-使用 Custom hook 進行表單的驗證
系列文
用30天更加認識 React.js 這個好朋友32

尚未有邦友留言

立即登入留言