사용자로부터 숫자를 입력받기 전에, input 요소와 관련된 키보드 이벤트에 관해 먼저 알아보겠습니다.
위 이벤트의 실행 순서는 나열한 순서대로 실행됩니다.
focus → keydown → keypress → input → keyup → change → blur
input 요소가 text type
인 경우, 모든 텍스트 문자열 입력이 가능합니다.
우리는 숫자값만 입력받는 input을 만들어야 합니다.
그럴러면, 사용자로부터 숫자 이외의 값을 입력받는 것은 최대한 제한하는 것이 좋을 것 같습니다.
이때 사용 가능한 이벤트로는, keydown
, input
, change
이벤트가 적당할 것 같습니다.
리액트에서 input 이벤트보다 change 이벤트를 사용할 것을 권장하고 있으니 change
이벤트를 이용해 사용자의 입력값을 제한해보도록 하겠습니다.
(keydown
이벤트의 경우에는 입력받은 key
의 값을 통해 걸러내야 하는 경우의 수가 change
이벤트보다 더 존재하다보니 사용하지 않게 되었습니다.)
일반적으로 text input
의 입력값에 전달되는 값의 타입은 string
입니다.
입력 받은 숫자를 저장해야 할 때, 문자열이 아닌 숫자형으로 저장해야 한다면 변형이 필요합니다.
문자열을 숫자(정수) 로 변환할 수 있는 방법에는 여러가지가 있습니다.
Number
+
단항 연산자parseInt
Number
메서드는 문자열을 숫자형으로 변환할 때, 아래의 규칙이 적용됩니다.
문자열의 처음과 끝 공백이 제거됩니다. 공백 제거 후 남아있는 문자열이 없다면
0
, 그렇지 않다면 문자열에서 숫자를 읽습니다. 변환에 실패하면NaN
이 됩니다. 모던 javascript 튜토리얼 참고
정리해보면,
숫자로만 구성된 문자열은 숫자로 변형되고,
문자열의 앞뒤 공백을 제거하고 난 후, 빈 문자열인 경우에는 0
이 되지만,
숫자가 아닌 문자열이 하나라도 포함되어 있을 경우 NaN
값이 됩니다.
const one = Number('123'); // 123
const two = Number(''); // 0
const three = Number('123a'); // NaN
const four = Number(' 123 '); // 123
const five = Number(' 12 3'); // NaN
+
단항 연산자는 Number
메서드와 같은 방식으로 작동합니다.
+
단항 연산자는 +
뒤에 오는 값이 숫자가 아닌 경우에만, 숫자형으로 변환 됩니다.
parseInt
메서드는 앞의 메서드들과 조금 다릅니다.
이 메서드는 앞에서부터 숫자를 읽을 수 있을 때까지 읽고, 값을 변형합니다.
숫자가 아닌 문자열이 숫자와 함께 포함되어 있어도, 숫자로 변형됩니다.
단, 숫자가 문자열보다 앞에 있을 경우에만 가능합니다. 이때, 빈 문자열은 숫자 앞에 있어도 상관없습니다.
하지만, 빈 문자열만 있는 경우에는 NaN
값을 표시합니다. 숫자가 없기 때문입니다.
const one = parseInt('123'); // 123
const two = parseInt(''); // NaN
const three = parseInt('123a'); // 123
const four = parseInt(' 12a3px'); // 12
const five = parseInt(' 12 3'); // 12
사용자가 입력된 값에 숫자를 덧붙여서 입력할 수도 있지만, 기존 값을 지울 경우에는 빈 문자열로 평가됩니다. 이때, 화면에 NaN
값이 표시되면 안되겠죠?
따라서, 빈 문자열이 0
으로 평가되는 Number
메서드를 이용해 문자열을 숫자형으로 변경합니다.
const [value, setValue = React.useState<number>(1);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(e.target.value);
setValue(value);
}
하지만, 위의 방법만으로는 문제가 해결되지 않습니다.
기존의 값을 모두 지운 경우에는 0
으로 표시되도록 했지만, 숫자가 아닌 문자열을 입력하면 NaN
으로 표기되기 때문인데요.
NaN
값을 제어하기 위해 관련 메서드에 대해 알아보겠습니다.
isNaN
메서드는 매개변수로 받은 값을 Number 타입으로 변경하는 과정을 거치는데, 그 과정에서 0
과 1
로 변경되는 것들이 있기 때문에 완전히 NaN
값을 판별하지 못합니다.
더 엄격하게 NaN 값을 검사하려면, Number.isNaN
메서드를 사용합니다.
이 메서드의 경우, 인자로 들어온 값을 Number 타입으로 변경하지 않고 값을 평가합니다.
타입스크립트에서 이를 사용할 때, 매개변수에 지정된 타입을 확인해보면 그 차이를 확인할 수 있습니다.
isNaN
의 매개변수 타입은 number
타입으로 지정되어 있기 때문에, 매개변수 값이 숫자가 아니라면 isNaN(Number(value))
와 같이 사용해야 합니다.
이와 달리, Number.isNaN
의 매개변수 타입은 unknown
으로 지정되어 있기 때문에, Number 타입을 전달하지 않아도 오류가 발생하지 않습니다.
isNaN(''); // 0 => false
isNaN('hello'); // NaN => true
isNaN(false); // 0 => false
isNaN(true); // 1 => false
isNaN([]); // 0 => false
isNaN({}); isNaN(undefined); // NaN => true
앞서, Number
메서드는 인자로 들어온 값을 숫자형으로 바꾸는 과정에서, 문자열이 1개라도 포함되어 있다면, NaN
값을 리턴한다고 했습니다. 이때, isNaN
메서드를 사용하면 숫자가 아닌 문자열을 입력했을 때 그 값을 걸러낼 수 있습니다.
const [value, setValue = React.useState<number>(1);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(e.target.value);
if (isNaN(value)) return;
setValue(value);
}
이제 숫자와 빈 문자열을 제외한 다른 문자열 입력이 되지 않도록 했으니, setValue
를 이용해 input
의 값을 설정해주면 숫자만 입력이 가능해집니다.
여기서부터는 필요한 과정일 수도 있고 아닐 수도 있습니다.
보통 사용자로부터 숫자를 입력받는 경우에는, +
, -
버튼과 함께 수량을 입력 받는 쇼핑몰 사이트에서 많이 볼 수 있습니다.
이때, 수량이 0
으로 입력됐다면 이 상태로 장바구니에 추가하거나, 주문할 수 없기 때문에 조정 과정이 필요합니다.
그런데 이를 change
이벤트에서 조정하면 어떤 일이 발생할까요?
const onChange = (e: React.ChanveEvent<HTMLInputElement>) => {
const value = Number(e.target.value);
if (Number.isNaN(value)) return;
if (value === 0) return;
setValue(value);
}
바로 backspace
, delete
키와 같은 기존 입력값을 지우기 위해 사용되는 키의 입력이 허용되지 않는 문제가 발생합니다.
backspace
키가 입력될 때 value
값이 0으로 평가되어 value === 0
구문에서 빠져 나오므로 더이상 코드의 4번째 줄인 setValue
가 실행되지 않아서 새로운 값으로 값을 변경할 수 없는 것이죠.
따라서, 기존에 '3'이 입력된 값에 '1'을 추가하여 13 혹은 31을 만들 수는 있어도, '3'을 따로 지울 수 없는 문제가 발생합니다.
이때, blur
이벤트를 사용하여 이 문제를 해결할 수 있습니다.
blur
이벤트는 사용자의 입력이 완료되고 input 엘리먼트에 대한 포커스가 해제됐을 때 발생합니다. 따라서, 사용자가 0
을 입력하더라도 입력값을 초기화할 수 있습니다.
const onBlur = (e: React.FocusEvent<HTMLInputElement>) => {
if (e.target.value === '0') {
setValue(1); // 초기화할 수량 입력
}
}
정리 주셔서 감사합니다~!