[React] input에 숫자만 들어가게 하기 + 세자리 콤마 넣기

Rachaen·2022년 4월 14일
0

[Frontend] 이것저것

목록 보기
1/7
post-thumbnail

input

        <input
          ref={priceRef}
          name="price"
          type="text"
          placeholder="가격(선택사항)"
          maxLength="12"
          onKeyDown={handlePrice}
          onChange={priceModify}
        />

저는 onKeyDown과 onChange를 같이 설정하였습니다.


(스타일링은 아직 안 했습니다...ㅎㅎ)

onKeyDown

  const handlePrice = (event) => {
    if (
      (event.keyCode > 47 && event.keyCode < 58 ||
      event.keyCode === 8 || //backspace
      event.keyCode === 37 ||
      event.keyCode === 39 || //방향키 →, ←
      event.keyCode === 46 //delete키
    ) {
      return;
    } else {
      event.preventDefault();
    }
  };

keyDown: 숫자와 backspace, 방향키, delete키를 제외한 다른 키가 눌리면 이벤트를 처리하지 않습니다. 하지만 여기서 문제점은 영문에서는 키를 눌렀을 때 이벤트가 잘 막아지지만 한글에서는 안 막아진다는 것이었습니다. 그래서 저는 onChange도 같이 설정해 주었습니다.

onChange

값이 바뀔 때 input value를 바꿔주면 되겠다는 생각이 들어서 onChange를 사용하였습니다.
keyUp을 사용해볼까 고민도 해보았지만 keyUp을 하면 keyDown에서 막았던 문자들이 같이 들어와서 사용하지 않았습니다.

쉼표 넣기

 let data = event.nativeEvent.data; // 어떤 값이 들어왔는지
let value = priceRef.current.value; // 현재 input의 전체값을 받아온다

// 받아온 값이 숫자일 경우 쉼표만 제대로 맞춰주면 된다
if (data >= 0 && data <= 9) {
      let onlyNumber = Number(value.replaceAll(',', ''));
      const formatValue = onlyNumber.toLocaleString('ko-KR');
      priceRef.current.value = formatValue;	// input value 변경해주기
    } else { // 숫자가 아닌 경우에는 들어온 문자만 지워준다.
      let priceExp = /^[,0-9]/g;
      if (!priceExp.test(data)) {
        const formatValue = value.replaceAll(/[^,0-9]/g, '');
        priceRef.current.value = formatValue; // input value 변경해주기
      }

쉼표 넣기는 간단하게 이 코드만 하셔도 되지만 문제점이 있습니다.

문제발생1


숫자를 입력했지만 마음이 바뀌어 input을 비어있게 하고 싶어서 backspace 키를 눌렀지만 input이 비지 않고 0으로 남습니다.
data가 null이면 else에 걸려야 하는 것 아닌가?! 싶었는데....
data가 null일 때
data >= 0 && data <= 9 에서 true 가 나왔습니다!!
뭐지 이 점에서는 따로 다뤄봐야겠습니다...ㅠ
data === 0false 로 나오므로
data === '0' || (data > 0 && data <= 9) 로 고치면 될까 싶었는데

문제발생2


흠...
우선 data === 0 이 아닌 data === '0'을 쓴 이유는 data는 문자입니다. ===은 형식도 확인하기 때문에 형식을 맞춰줘야 true가 나올 수 있죠.
==는 값만 다루기 때문에 data == 0을 쓴다면 true로 나온답니다!!ㅋㅋ
어쨌든 이 방법은 backSpace도 null로 처리하기 때문에 else문으로 넘어가네요ㅋㅋㅋㅋ

해결

그래서 value가 빈 값일 때 return을 시켜주는 방법을 택했습니다.

if (value === '') {
    return;
  }

최종 onChange

  const priceModify = (event) => {
    let data = event.nativeEvent.data;
    let value = priceRef.current.value;
    if (value === '') {
      return;
    } 
    if (data >= 0 && data <= 9) {
      let onlyNumber = Number(value.replaceAll(',', ''));
      const formatValue = onlyNumber.toLocaleString('ko-KR');
      priceRef.current.value = formatValue;
    } else {
      let priceExp = /^[,0-9]/g;
      if (!priceExp.test(data)) {
        const formatValue = value.replaceAll(/[^,0-9]/g, '');
        priceRef.current.value = formatValue;
      }
    }
  };

이렇게만 하시면 화면상으로는 잘 되실 겁니다!
순수js에서도 getElementById 등등 이용해서 바꿀 수 있을 듯 하네요..(예상)
저는 리액트를 사용해서 state값을 업데이트를 해주어야하기 때문에 위 코드에서 set해주는 함수도 추가하하고 이것저것 했네요 ㅎㅎ

  • 가격 입력을 안 하면 가격제안받기가 비활성화가 되고 가격을 입력하면 활성화가 됩니다.
  • 0을 누르면 나눔으로 바뀝니다.

참고

키코드 참고
숫자만 입력 참고
쉼표 넣기 참고

profile
개발을 잘하자!

0개의 댓글