React

React : Form 유효성 검사 3가지 방식

죽이죽이 2024. 2. 26. 13:09

폼 제출 시 (Submit)

※ 설명
- 입력을 완전히 마친 후 제출을 하기 전까지 경고를 표시하지 않는다.

- 불필요한 피드백은 줄지만, 피드백이 너무 늦을 수 있다.

※ 예시 코드
import { useRef, useState } from "react";

const SimpleInput = (props) => {
  const nameRef = useRef();
  const [name, setName] = useState("");
  const [nameValid, setNameValid] = useState({
    isNotEmpty: false,
    isTouched: false,
  });

  const nameInputHandler = (e) => {
    setName(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    setNameValid((prev) => ({ ...prev, isTouched: true }));

    if (!name.trim()) {
      console.log("submit fail");
      setNameValid((prev) => ({ ...prev, isNotEmpty: false }));
      return;
    }

    setNameValid((prev) => ({ ...prev, isNotEmpty: true }));
    setName("");
  };

  const isNameValid = !nameValid.isNotEmpty && nameValid.isTouched;
  const formClasses = isNameValid ? "form-control invalid" : "form-control";

  return (
    <form onSubmit={handleSubmit}>
      <div className={formClasses}>
        <label htmlFor="name">당신의 이름은?</label>
        <input type="text" id="name" ref={nameRef} value={name} onChange={nameInputHandler} />
        {isNameValid && <p className="error-text">이름값은 빈 값이 아니어야 됩니다.</p>}
      </div>
      <div className="form-actions">
        <button>제출하기</button>
      </div>
    </form>
  );
};

export default SimpleInput;

 

 

 

초점 잃을 때 (lose focus)

※ 설명
- 하나의 input에 대해 입력을 완전히 마치고 Blur 되기 전까지 경고를 표시하지 않는다.
- 적당한 수준의 피드백이 주어져서 많이 선호된다.

※ 예시 코드
import { useRef, useState } from "react";

const SimpleInput = (props) => {
  const nameRef = useRef();
  const [name, setName] = useState("");
  const [nameValid, setNameValid] = useState({
    isNotEmpty: false,
    isTouched: false,
  });

  const nameInputChangeHandler = (e) => {
    setName(e.target.value);
  };

  // 초점을 잃었을 경우
  const nameInputBlurHandler = () => {
    setNameValid((prev) => ({ ...prev, isTouched: true }));

    if (name.trim() === "") {
      setNameValid((prev) => ({ ...prev, isNotEmpty: false }));
      return;
    }

    setNameValid((prev) => ({ ...prev, isNotEmpty: true }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    setNameValid((prev) => ({ ...prev, isTouched: true }));

    if (name.trim() === "") {
      console.log("submit fail");
      setNameValid((prev) => ({ ...prev, isNotEmpty: false }));
      return;
    }

    setNameValid((prev) => ({ ...prev, isNotEmpty: true }));
    setName("");
  };

  const isNameValid = !nameValid.isNotEmpty && nameValid.isTouched;
  const formClasses = isNameValid ? "form-control invalid" : "form-control";

  return (
    <form onSubmit={handleSubmit}>
      <div className={formClasses}>
        <label htmlFor="name">당신의 이름은?</label>
        <input
          type="text"
          id="name"
          ref={nameRef}
          value={name}
          onChange={nameInputChangeHandler}
          onBlur={nameInputBlurHandler} // 초점을 잃었을 경우
        />
        {isNameValid && <p className="error-text">이름값은 빈 값이 아니어야 됩니다.</p>}
      </div>
      <div className="form-actions">
        <button>제출하기</button>
      </div>
    </form>
  );
};

export default SimpleInput;

 

 

 

매 번 키보드 칠 때 (on every keystroke)

※ 설명
- 입력하는 도중 경고가 지속적으로 발생한다.
- 올바르지 않은 형태의 값에 대해 바로 피드백을 준다.

※ 예시 코드
import { useRef, useState } from "react";

const SimpleInput = (props) => {
  const nameRef = useRef();
  const [name, setName] = useState("");
  const [nameValid, setNameValid] = useState({
    isNotEmpty: false,
    isTouched: false,
  });

  // 사용자가 키보드 입력 시 계속 유효성 검사
  const nameInputChangeHandler = (e) => {
    setName(e.target.value);
    setNameValid((prev) => ({ ...prev, isTouched: true }));

    if (name.trim() === "") {
      setNameValid((prev) => ({ ...prev, isNotEmpty: false }));
    } else {
      setNameValid((prev) => ({ ...prev, isNotEmpty: true }));
    }
  };

  const nameInputBlurHandler = () => {
    setNameValid((prev) => ({ ...prev, isTouched: true }));

    if (name.trim() === "") {
      setNameValid((prev) => ({ ...prev, isNotEmpty: false }));
      return;
    }

    setNameValid((prev) => ({ ...prev, isNotEmpty: true }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    setNameValid((prev) => ({ ...prev, isTouched: true }));

    if (name.trim() === "") {
      console.log("submit fail");
      setNameValid((prev) => ({ ...prev, isNotEmpty: false }));
      return;
    }

    setNameValid((prev) => ({ ...prev, isNotEmpty: true }));
    setName("");
  };

  const isNameValid = !nameValid.isNotEmpty && nameValid.isTouched;
  const formClasses = isNameValid ? "form-control invalid" : "form-control";

  return (
    <form onSubmit={handleSubmit}>
      <div className={formClasses}>
        <label htmlFor="name">당신의 이름은?</label>
        <input
          type="text"
          id="name"
          ref={nameRef}
          value={name}
          onChange={nameInputChangeHandler}
          onBlur={nameInputBlurHandler}
        />
        {isNameValid && <p className="error-text">이름값은 빈 값이 아니어야 됩니다.</p>}
      </div>
      <div className="form-actions">
        <button>제출하기</button>
      </div>
    </form>
  );
};

export default SimpleInput;