iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
Modern Web

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

Day12-React 表單驗證篇-使用 Custom hook 進行表單的驗證

這次我們使用 Custom hook 進行表單的驗證。

首先我們建立一個檔案叫 useInputValidate.js ,裡面將會寫一個 Custom hook,分兩個部分完成。

第一步

先寫出 hook 的函式,並產生 state,這裡使用 useReducer 管理 state。

此 hook 接受一個參數 validateValue,因為不同的輸入內容驗證輸入有效的方式也會不同,所以就把驗證的函式做為參數傳入。

const initialInput = {
  value: '',
  isTouched: false,
};

const inputReducer = (state, action) => {
  switch (action.type) {
    case "INPUT":
      return { value: action.value, isTouched: state.isTouched };
    case "BLUR":
      return { isTouched: true, value: state.value };
    case "Reset":
      return { isTouched: false, value: '' };
    default:
      return state;
  }
}

const useInputValidate = (validateValue) => {
  const [input, dispatch] = useReducer(inputReducer, initialInput);
}

第二步

加上相關的事件函式及回傳值就完成此 hook。

const initialInput = {
  value: "",
  isTouched: false
};

const inputReducer = (state, action) => {
  switch (action.type) {
    case "INPUT":
      return { value: action.value, isTouched: state.isTouched };
    case "BLUR":
      return { isTouched: true, value: state.value };
    case "Reset":
      return { isTouched: false, value: "" };
    default:
      return state;
  }
};

const useInputValidate = (validateValue) => {
  const [input, dispatch] = useReducer(inputReducer, initialInput);

  const valueIsValid = validateValue(input.value);
  const hasError = !valueIsValid && input.isTouched;

  const onChangeValue = (e) => {
    dispatch({ type: "INPUT", value: e.target.value });
  };

  const onBlurValue = () => {
    dispatch({ type: "BLUR" });
  };

  const reset = () => {
    dispatch({ type: "RESET" });
  };

  return {
    value: input.value,
    isValid: valueIsValid,
    hasError,
    onChangeValue,
    onBlurValue,
    reset
  };
};

實際使用

接著我們來實際使用一下這個 hook,將 hook 回傳的內容進行解構賦值,加到會用到它們的地方即可。

另外記得給 hook 一個函式當作參數,用來驗證輸入值用。

import "./styles.css";

import useInputValidate from "./useInputValidate";

const emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
const isNotEmpty = (value) => value.trim() !== "";
const isEmailFormat = (value) => emailRule.test(value);

const SimpleForm = () => {
  const {
    value: name,
    isValid: nameIsValid,
    hasError: nameError,
    onChangeValue: onChangeName,
    onBlurValue: onBlurName,
    reset: resetName
  } = useInputValidate(isNotEmpty);

  const {
    value: email,
    isValid: emailIsValid,
    hasError: emailError,
    onChangeValue: onChangeEmail,
    onBlurValue: onBlurEmail,
    reset: resetEmail
  } = useInputValidate(isEmailFormat);

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

    if (!nameIsValid || !emailIsValid) {
      return;
    }

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

    // reset
    resetName();
    resetEmail();
  };

  const nameInputClasses = nameError ? "invalid" : "";
  const emailInputClasses = emailError ? "invalid" : "";

  return (
    <form onSubmit={onFormSubmit}>
      <label htmlFor="name">Your Name</label>
      <input
        type="text"
        id="name"
        onChange={onChangeName}
        onBlur={onBlurName}
        value={name}
        className={nameInputClasses}
      />
      {nameError && <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}
      />
      {emailError && <p className="error-text">Please enter a valid email.</p>}
      <button disabled={!nameIsValid || !emailIsValid}>Submit</button>
    </form>
  );
};

export default SimpleForm;

程式碼範例(codesandbox)

透過以上的方式,如果表格欄位一多的時候,就不用再寫許多相似的程式碼,讓整個表單元件的程式碼變得更加可讀。


上一篇
Day11-React 表單驗證篇-不使用 hook 或第三方函式庫
下一篇
Day13-React 表單驗證篇-使用第三方函式庫 Formik 進行表單的驗證
系列文
用30天更加認識 React.js 這個好朋友32

尚未有邦友留言

立即登入留言