본문 바로가기

개발/React.js

React 주민등록번호 컴포넌트

1. 목적

[인수 조건]

Given

개발자는 주민등록번호 유효성 검증을 위한 정규식을 이용한다.

코드가 길어질 경우 라이브러리 React-hook-form을 사용할 수 있다.

text input 2개로 구성된 컴포넌트로 구현한다.

When

주민등록번호 컴포넌트 GUI와 유효성 검증하는 함수로 각각 분리한다.

Then

1. 00년생 이전/이후와 생년월일, 성별 케이스별로 나누어

주민등록번호의 뒷 번호 첫 번째 자리까지 유효성 검증을 진행한다.

2. 실시간으로 유효성 검증이 진행된다.

3. 올바르지 않은 주민번호 입력시 가이드 텍스트가 표시된다.

 

[설명]

보상 안내 받는 이와 예금주의 주민등록번호를 받았을 때 실시간 유효성 검증 기능이 있는 주민등록번호 컴포넌트를 구현한다.

  • 케이스는 00년생 이전과 이후로 나뉘며
  • 앞, 뒷 번호 자릿수
  • 생년월일 범위에 속하는지
  • 뒷 번호가 체계에 맞게 구성되어 있는지 검증.
  • 앞자리 6자리가 모두 채워졌을 경우, 다음 텍스트박스로 커서를 이동한다.

[참고]

  • 주민번호 검증 가능해야함
  • 검증은 02년생 이전과 이후로 나뉨
  • 앞자리 뒷자리 모두 검증 가능해야함.
  • 디자인 제외 text input 2개로 구성된 컴포넌트
  • 올바르지 않은 주민번호 입력시 가이드 텍스트 표시되어야함 (옵션)
  • 실시간 유효성 검증 기능

2. 주민등록번호 체계

앞자리

  1. 연도

뒷자리

  1. 성별 (dash가 없을 경우 7번째 자리)
  2. 이후 번호들은 아래 전체적인 주민번호 계산 방법 참고

3. 필요한 기능

기본 조건

  • 숫자 이외의 값을 넣을 수 없다. (입력값 정수 체크)
  • 앞자리는 6자리를 넘을 수 없고, 뒷자리는 7자리를 넘을 수 없다.
  • 앞자리는 6자리여야 하고, 뒷자리는 7자리여야 한다.
  • 크기만큼 입력됐다면 다음 필드로 포커스가 이동해야 한다.
  • 앞자리가 빈칸일 경우 뒷자리 텍스트박스를 입력할 수 없다.
  • 두 텍스트박스가 공백일 경우 필수 항목이라는 표시를 해야 한다.

앞자리

  • 정규식 - 대시 없는 경우
    • const regex = /^\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{7}$/
      • ^: 문자열의 시작
      • \d: 숫자
      • {2}: 바로 앞의 표현식이 두 번 반복되어야 함. 여기서는 /d{2} 니까 두자리 숫자
      • (0[1-9]|1[0-2]): 01~09 또는 10~12의 두 자리 숫자
      • (0[1-9]|[1-2][0-9]|3[0-1]): 01~09 또는 10~29 또는 30, 31 중 하나의 두 자리 숫자
      • [-] : 대시가 포함되어야 함.
      • \d{7}: 7자리 숫자
      • $: 문자열의 끝
  • 2월일 경우 28일까지여서 추가 처리가 필요할 것 같다.

뒷자리

  • 전체적인 체크로직 검증
  1. 주민등록번호의 앞 6자리의 수에 처음부터 차례대로 2,3,4,5,6,7 을 곱한다.
  2. 그 다음, 뒤 7자리의 수에 마지막 자리만 제외하고 차례대로 8,9,2,3,4,5 를 곱한다.
  3. 이렇게 곱한 각 자리의 수들을 모두 더한다.
  4. 모두 더한 수를 11로 나눈 나머지를 구한다.
  5. 이 나머지를 11에서 뺀다.
  6. 이렇게 뺀 수가 두 자릿수이면, 즉 10보다 크면 다시 11로 나누어 나머지 값을 구한다.
  7. 이렇게 해서 나온 최종 값을 주민등록번호의 마지막 자리 수와 비교해서 같으면 유효한 번호이고 다르면 잘못된 값이다.
  • 성별 검증
    • 성별부분이 1 ~ 4 가 아닌 경우
    •   // 연도 계산 - 1 또는 2: 1900년대, 3 또는 4: 2000년대
        cc = (genda == "1" || genda == "2") ? "19" : "20";
        if (isValidDate(cc+yy+mm+dd) == false) {
          alert("주민등록번호 앞자리를 다시 입력하세요.");
          return false;
        }
    • 1: 1900년대에 출생한 남자
    • 2: 1900년대에 출생한 여자
    • 3: 2000년대에 출생한 남자
    • 4: 2000년대에 출생한 여자
    • 5: 1900년대에 출생한 외국인 남자
    • 6: 1900년대에 출생한 외국인 여자
    • 7: 2000년대에 출생한 외국인 남자
    • 8: 2000년대에 출생한 외국인 여자

전체 주민등록번호 유효성 체크


4. 경우의 수

성별전체

남성 1900년대 01, 03~12 02 01~31 01~30 28 1 통합 계산
2000년대 3
여성 1900년대 2
2000년대 4

+ 외국인도 있을 수 있다. (승림 과장님 확인)


5. 논리 흐름 예상

→ 컴포넌트 1개, useCheckKoreanID Hook 1개, 유효성 검증 Util 함수 1개

  1. 주민등록번호 input text 2개를 하나의 string으로 모아서 검증하는 함수 → 1900년대 / 2000년대 분간
  2. <KoreanIDCheck /> 컴포넌트
    1. text box 2개의 상태가 변경될 때마다 모든 숫자를 모아서 useEffect로 함수 호출
      1. props로 useCheckKoreanID에 전달
      2. KoreanIDCheckUtil에서 검증 결과 반환
      3. useCheckKoreanID 훅에서 가이드 텍스트로 상태 알려준다.
      4. props
        1. 주민등록번호 전체 string ➔
        2. 전체 유효 상태 체크 boolean ←
        3. 가이드 메시지 string ←

[Sequence Diagram]

 
  • <RegNumber />
    • Props
      • setIsValid : 컴포넌트 바깥에서 상태 저장을 위한 validation 검증 여부
      • setRegistrationNumber : 컴포넌트 바깥에서 상태 저장을 위한 validation 검증 여부
  • useRegNumber
    • Custom Hooks
      • props를 유효성 검증 Util에 옮겨주는 역할
      • 유효성 검증 부위에 따른 가이드 메시지 전달 역할
  • validRegNumberUtil
    • 내부에 순수함수들 모음집 만들 예정…
    • Util 함수
      • 앞자리
        • 숫자가 아닌 값을 입력한 경우
        • 연월일(YYMMDD) 형식이 제대로 구성되어 있는가?
        • 앞자리가 6자리가 아닌 경우
        • 실제 달력에 있는 날짜인가 아닌가
      • 뒷자리
        • 한국인인가, 외국인인가?
        • 숫자가 아닌 값을 입력한 경우
        • 첫 번째 자리가 연도에 따라 성별이 정확히 입력되었는가?
          • 1~4인가
            • 1 또는 2: 1900년대, 3 또는 4: 2000년대인가?
          • 전체적으로 유효한 주민번호가 맞는가
            • ABCDEF - GHIJKLM
            • 검증 공식: M = (11 - ((2×A + 3×B + 4×C + 5×D + 6×E + 7×F + 8×G + 9×H + 2×I + 3×J + 4×K + 5×L) % 11)) % 10
        • 7자리가 아닌 경우
        • 7자리일 경우 전체 주민등록번호가 유효한지 계산

7. 구조

페이지에서 컴포넌트 호출 방법

<RegNumber
      setIsValid={setIsValid}
      setRegistrationNumber={setRegistrationNumber}
  />

컴포넌트 내부

export const RegNumber = (props: RegNumberProps) => {
    const {
        isValidFrontRegNumber,
        isValidBackRegNumber,
        frontRegNumber,
        backRegNumber,
        validRegNumberUtil,
    } = useRegNumber();

    useEffect(() => {
        if (props.setIsValid) {
            props.setIsValid(isValidFrontRegNumber && isValidBackRegNumber);
        }

        if (props.setRegistrationNumber) {
            props.setRegistrationNumber(frontRegNumber + backRegNumber);
        }
    }, [
        isValidFrontRegNumber,
        isValidBackRegNumber,
        frontRegNumber,
        backRegNumber,
    ]);

Custom Hook

export const useRegNumber = () => {
    const [isValidFrontRegNumber, setValidFrontRegNumber] =
        useState<boolean>(false);
    const [isValidBackRegNumber, setValidBackRegNumber] =
        useState<boolean>(false);
    const [frontRegNumber, setFrontRegNumber] = useState<string>("");
    const [backRegNumber, setBackRegNumber] = useState<string>("");

    const validRegNumberUtil = (
        frontRegNumber: string,
        backRegNumber: string
    ) => {
        console.log("frontRegNumber : ", frontRegNumber);
        console.log("backRegNumber : ", backRegNumber);
        const regExpFront = /^[0-9]{6}$/;
        const regExpBack = /^[1-9][0-9]{6}$/;
        if (frontRegNumber || backRegNumber) {
            const isValidFrontRegNumber = regExpFront.test(frontRegNumber);
            const isValidBackRegNumber = regExpBack.test(backRegNumber);
            setValidFrontRegNumber(isValidFrontRegNumber);
            setValidBackRegNumber(isValidBackRegNumber);
            setFrontRegNumber(frontRegNumber);
            setBackRegNumber(backRegNumber);
        }
    };

공통 Utill

  • 글자수 제한, 문자열, 영문 타입 등

8. 관련 정규식 및 라이브러리 확인

  • 주민등록번호 관련 정규식
  • 주민등록번호 전체 계산 검증 공식
  • React-hook-form 라이브러리를 적용할 때와 적용하지 않을 때 장단점

'개발 > React.js' 카테고리의 다른 글

Dynamic Route - Slug  (0) 2024.09.13
Xlsx parsing + react-table  (0) 2024.09.13
OAuth 인증 - 인가에 대하여  (0) 2024.09.13
전역 상태 관리 라이브러리 - Zustand vs Recoil  (0) 2024.09.13
파일 Drag & Drop  (0) 2024.09.13