React에서 HTML input 속성을 활용한 실시간 유효성 검증 구현

2025. 8. 27. 19:27·TIL

0. 개발 목표 

  • React에서 HTML5 input 속성만으로 이메일/비밀번호 유효성 검증 구현
  • 사용자 입력과 동시에 실시간 검증 피드백(에러 메세지) 제공
  • 라이브러리 없이 브라우저 내장 기능만 활용

1. 오늘 한 것 (What I Did)

  • React에서 로그인 폼 컴포넌트 구현
  • 이메일 형식 검증 (type="email", required)
  • 복잡한 비밀번호 규칙 검증 (pattern, minLength, required)
  • 실시간 입력 검증 기능 구현
  • 브라우저의 checkValidity(), reportValidity() API 활용
  • 폼 제출 시 전체 검증 로직 구현

2. 새로 이해한 것 (What I Learned)

2-1. JavaScript 변수 스코프의 함정

const handleChange = (e) => {
  let errorMessage = '에러 발생!';
};

return (
  <div>
    {errorMessage && <p>{errorMessage}</p>} {/* ❌ ReferenceError */}
  </div>
);
  • 함수 내부 지역 변수는 JSX 렌더링 시점에서 접근 불가. 
  • React는 상태(useState)로 컴포넌트 전반에서 데이터 공유.

2-2. e.target vs e.target.value 구분

// 헷갈렸던 실수 
const inputUsername = e.target.value; // 문자열
console.log('유효한가?', inputUsername.validity.valid); // ❌ 문자열에는 validity 없음

// 올바른 이해 
const inputValue = e.target.value;    // 사용자 입력 텍스트 (문자열)
const inputElement = e.target;        // HTML input 요소 (객체)
console.log('유효한가?', inputElement.validity.valid); // ✅ 정상 작동
  • e.target은 DOM 요소, e.target.value는 입력값. 각각의 역할을 명확히 구분.

2-3. setCustomValidity의 악순환 문제

// ❌ 악순환 구조
if (!inputElement.validity.valid) {
  inputElement.setCustomValidity('에러'); // 이 순간부터 계속 invalid
}

// ✅ 단순하고 안정적
const handleChange = (e) => {
  if (e.target.value.length > 0 && !e.target.checkValidity()) {
    e.target.reportValidity();
  }
};
  • valid가 false로 고정되어 조건문이 항상 true.
  • 브라우저 기본 검증만 활용하는 것이 안정적.

2-4. 브라우저 검증 API 활용법

새로 배운 속성들 

inputElement.validity.valid           // 전체 검증 통과 여부
inputElement.validity.patternMismatch // 정규표현식 불일치
inputElement.validity.tooShort        // 최소 길이 미달
inputElement.validity.valueMissing    // 필수값 누락
inputElement.validationMessage        // 브라우저 생성 에러 메시지

inputElement.checkValidity()          // 검증 실행
inputElement.reportValidity()         // 에러 메시지 표시

2-5. form vs onClick의 차이점

문제

<button onClick={handleSubmit}>로그인</button>

const handleSubmit = () => {
  if (userPassword.length >= 9) { // 수동 검증만
    alert('성공!');
  }
};

해결

<form onSubmit={handleSubmit}>
  <button type="submit">로그인</button>
</form>

const handleSubmit = (e) => {
  e.preventDefault();
  if (!e.target.checkValidity()) {
    e.target.reportValidity(); // 브라우저 검증 활용
    return;
  }
  alert('성공!');
};
  • <form> 태그 없이도 검증 가능하지만 표준적이고 자동화된 처리를 위해 필요
  • type="submit" + onSubmit 조합으로 자동 검증
  • 접근성과 웹 표준 준수
  • 브라우저 자동완성 최적화

2-6. 실시간 검증의 UX 고려

  • 첫 글자부터 에러 표시 → 너무 공격적
  • 입력 완료 후 검증 → 늦은 피드백
  • 조건부 검증 → 복잡성 증가 
  • 브라우저 기본 검증만 활용하는 것이 안정적.

찾은 방법: 입력 길이 조건 + checkValidity 조합

if (inputValue.length > 0 && !inputElement.checkValidity()) {
  inputElement.reportValidity();
}

3. 최종 코드 

// 목표
// 사용자 입력 검증 구현하기

// 조건
// 1.input 속성 이용하기

// 요구 사항 
// 1. 이메일은 username@example.com 형식 검증
// 2. 비밀번호는 9자 이상, 대문자, 소문자, 숫자 1개씩 이상 포함 
// 3. 이메일과 비밀번호 유효성 검사 각각 실시간 검사 실행 (사용자 입력과 동시에) 
// 4. 유효성 검사를 무사히 마친 뒤 로그인 버튼을 누르면 얼럿 창에 UserEmail 명시 


import styles from './LoginForm.module.css';

export default function LoginForm() {

  // 사용자명 입력 시 실행되는 함수 (입력과 동시에 유효성 검사 및 이메일 상태 업데이트 )
  const handleUserEmailChange = (e) => {
    const inputElement = e.target;
    const inputUserEmail= e.target.value; // 입력된 값을 변수에 저장

    // 이메일 형식 실시간 검사
    if (inputUserEmail.length > 0 && !inputElement.checkValidity()) {
      inputElement.reportValidity();
    }

  };

  // 비밀번호 입력 시 실행되는 함수 (입력과 동시에 유효성 검사)
  const handleUserPasswordChange = (e) => {
    const inputElement = e.target;
    const inputUserPassword = e.target.value; // 입력된 비밀번호를 변수에 저장

    // 비밀번호 형식 실시간 검사
    if (inputUserPassword.length > 0 && !inputElement.checkValidity()) {
      inputElement.reportValidity();
    }
  };


  // 로그인 버튼 클릭 시 실행되는 함수
  const handleSubmit = (e) => {
    e.preventDefault();

    // 제출 시점에 값 추출
    const formData = new FormData(e.target);
    const userEmail = formData.get('email');

    alert(`Welcome, ${userEmail} 😀! Login successful.`);
  };


  return (
    <div className={styles.container}>
      <form onSubmit={handleSubmit} noValidate={false}>
        <div className={styles.card}>
          {/* 제목 영역 */}
          <div className={styles.title}>
            <h1>Login</h1>
          </div>

          {/* 입력 필드 영역 */}
          <div className={styles.inputField}>
            <div>
              <label>
                Email
                <input
                  id="email"
                  name="email"
                  onChange={handleUserEmailChange}
                  type="email"
                  placeholder="username@example.com"
                  autoComplete="email"
                  required
                  title="올바른 이메일 형식을 입력해주세요"
                />
              </label>
            </div>

            <div>
              <label>
                Password
                <input
                  id="password"
                  name="password"
                  onChange={handleUserPasswordChange}
                  type="password"
                  placeholder="Enter your password"
                  pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{9,}" // 9자 이상, 대소문자와 숫자 포함
                  minLength={9}
                  autoComplete="current-password"
                  required
                  title="9자 이상, 대문자/소문자/숫자를 포함해주세요"
                />
              </label>
            </div>
          </div>

          {/* 로그인 버튼 영역 */}
          <div className={styles.button}>
            <button type="submit">Login</button>
          </div>
        </div>
      </form>
    </div>
  );
}
저작자표시 비영리 변경금지 (새창열림)
'TIL' 카테고리의 다른 글
  • [시행착오편] 디스코드 봇 만들기: 포스트 자동 생성 봇
  • JavaScript 공식 문서 읽기 1일 차
  • 2025-08-20 Props와 이벤트 객체 'e' 이해하기
  • 2025-08-19 React 공식 문서 - 상호작용 더하기
한비(BIBI)
한비(BIBI)
IT 업계에서 오랫동안 일 하고 싶습니다. 가능하다면 죽을 때까지 배우며 살고 싶습니다. 마케팅과 CX 분야에서 커리어를 쌓았습니다. 지금은 IT 업계에 더 깊이 있게 기여하고자 개발 공부를 하고 있습니다. 이 배움의 여정을 글로 남기고 싶어 블로그를 시작했습니다.
  • 한비(BIBI)
    0과 1로된 세상
    한비(BIBI)
  • 전체
    오늘
    어제
    • 분류 전체보기 (33)
      • 크래프톤 정글 (5)
      • Computer Science (10)
      • 읽고 쓰고 생각하기 (1)
      • 일하면서 배웁니다 (1)
      • TIL (15)
  • 링크

    • LinkedIn
    • Threads
    • Twitter
  • 인기 글

  • 태그

    크래프톤정글
    정글후기
    뉴스피드시스템
    운영체제구조
    gpt인프라
    컴퓨터과학입문
    CPU스케줄링
    시스템설계
    나만무프로젝트
    데이터시각화
  • hELLO· Designed By정상우.v4.10.4
한비(BIBI)
React에서 HTML input 속성을 활용한 실시간 유효성 검증 구현
상단으로

티스토리툴바