블로그 목록

쿠폰 코드 입력 Bottom Sheet 컴포넌트 — 7가지 요구사항과 4가지 트러블슈팅

2024-07-187 min read
ReactBottom SheetInputAOSiOS

쿠폰 입력 Bottom Sheet 컴포넌트를 구현하면서 다양한 문제를 맞닥뜨려 해결했던 방안을 소개합니다.

요구 사항

  1. 숫자 키패드 보이기
  2. 입력한 값 보이지 않기
  3. 숫자만 입력 가능하도록 제한
  4. 입력하면 다음 위치로 focus 이동, 값을 지우면 이전 위치로 focus 이동
  5. 입력하고 있는 위치에서 다음 인풋을 누르지 못하게 하기, 이전 인풋 누르지 못하게 하기
  6. 4자리 코드 입력하지 않을 경우 확인 버튼 비활성화
  7. 4자리 코드 입력, 확인 버튼 클릭 후 잘못된 값 입력 시 에러 메시지로 변경하고 값 reset 시키기

문제 상황

  • 값을 지우기 위해 인풋 클릭 시 값이 지워지지 않는 현상 (input 커서 문제)
  • AOS에서 input type='password'일 때, 입력된 값이 느리게 •로 변경되는 현상
  • iOS(Safari)에서 값을 reset 시켰으나 reset된 후 다시 원래 값으로 돌아오는 현상
  • auto complete 방지 (아직 못함)

요구 사항 1: 숫자 키패드 보이기

3가지 방법을 비교해봤다.

채택한 방법

<input type="password" inputMode="numeric" />

비교한 다른 방법

<input type="number" />
<input type="text" />

플랫폼별 키패드 동작

방법AOSiOS
password + inputMode="numeric" (채택)숫자 키패드숫자 키패드
type="number"숫자 키패드한글/영어 → 숫자로 변경한 키패드
type="text"한글/영어 키패드한글/영어 키패드

→ AOS·iOS 모두 처음부터 숫자 키패드가 뜨는 건 채택안뿐이다.

요구 사항 2: 입력한 값 보이지 않기

type='password'로 설정.

요구 사항 3: 숫자만 입력 가능하도록 제한

숫자인지 체크하여 입력되지 않도록 방지한다. e.target.value.length > 1이 있는 이유는 코드는 한 글자이기 때문에 입력되지 않도록 방지하는 것이다.

여담: type='number'일 땐 조건이 추가되어야 한다.

if (value === "e" || value === "-") return false;

'e', '-'가 숫자에 포함되기 때문에 예외 처리를 해주어야 한다. (예: 1.01e-12 = 10100000000)

요구 사항 4: 입력하면 다음 위치 focus 이동 / 지우면 이전 위치 focus

값이 들어오면 lastPosition(마지막 위치)이라는 state의 값을 변경한다.

  • 값이 있으면 +1
  • 값이 없으면 -1

onChange에 trigger가 있다. lastPosition(마지막 위치)이 변경되면 focus가 되도록 설정되어 있다.

요구 사항 5: 입력 중인 위치에서 다른 인풋 못 누르게 하기

1. readOnly 세팅

인풋readOnly 조건
첫 번째 Input두 번째 Input 값이 있으면 readOnly
두 번째 Input첫 번째 Input 값이 없거나, 세 번째 Input 값이 있으면 readOnly
세 번째 Input두 번째 Input 값이 없거나, 네 번째 Input 값이 있으면 readOnly
네 번째 Input세 번째 Input 값이 없으면 readOnly

2. focus됐을 경우

lastPosition(마지막 위치)으로 focus를 이동한다.

3. click했을 경우 (막을 필요가 없는 예외 처리)

lastPosition(마지막 위치)의 값이 있을 경우에는 lastPosition의 위치를 click한 위치로 옮긴다.

lastPosition(마지막 위치)이 변경되면 focus가 되도록 설정되어 있다.

요구 사항 6 & 7: 확인 버튼 비활성화 + 에러 메시지

API error일 경우 COU-004 errorCode일 경우엔 toast message를 표시하지 않고 화면에 표시하고, 값을 reset 시킨다.


트러블슈팅

1. 인풋 클릭 시 값이 지워지지 않는 현상 (input 커서 문제)

자동으로 focus가 이동하지 않고 인풋을 바로 클릭했을 때 클릭한 위치로 커서가 설정되기 때문에 값이 지워지지 않게 보이게 된다.

해결: 커서의 위치를 뒤로 보내주어 값이 지워질 수 있도록 설정. 시각적으로 헷갈리지 않도록 커서 색깔을 투명으로 지정.

여담: input[type='number']에는 setSelectionRange가 없다고 한다.

2. AOS에서 input type='password'일 때, 입력된 값이 느리게 •로 변경되는 현상

Input.Password에서 현상을 확인하고 CodeInput에서 현상을 비교하였다. (vanilla input[type='password']에서도 현상 확인)

원래 input[type='password']의 특성이었다.

그러나 •로 빠르게 변하는 순간이 있는데 그건 바로 다음 문자가 입력될 때였다. 그리하여 생각해낸 약간의 꼼수(?)

  1. ref 값에 value 뒤에 값을 하나 더 붙여준다.
  2. 원본 codes 데이터는 변경하지 않기 때문에 refs.current[index].value의 값은 그대로 돌아온다.

처음엔 maxLength가 원인이라고 생각했는데, ref 값이 input[value] 값을 따라오는 것을 발견.

3. iOS(Safari)에서 값을 reset 시켰으나 reset된 후 다시 원래 값으로 돌아오는 현상

기존 코드는 react-hook-form으로 codes state를 관리했으나 useState로 변경하니 발생하지 않았다. react-hook-form의 로직이 더 지연이 있어 발생하는 것으로 추측 중…

실제로 setTimeout으로 reset value에 지연을 주면 발생하지 않았음.