프론트엔드 정복하기
정규식과 lastIndex / onchange 이벤트에서 정규식 조건이 발동하지 않는 이유 본문
문제
input 태그에서 change가 일어날 때마다 어떤 정규식(숫자인지 체크)을 통과하면 alert 를 띄우도록 했다.
const regExp = /\d/g;
export function TextBox(){
const [value, setValue] = useState('');
const handleChange =(e)=>{
const currentValue = e.currentTarget.value;
if(regExp.test(currentValue)){
alert('숫자를 입력하실 수 없습니다.')
}
setValue(currentValue);
}
.....
}
<input onChange={handleChange} value={value} />
--> 처음 숫자가 입력되었을 때 정규식 관련 조건문이 잘 작동되었다.
하지만 alert가 띄어진 이후 다시 숫자를 입력하면 조건이 작동하지 않았다.
원인
g 플래그의 특징
- RegExp 객체는 g 옵션이 있을 때, 'lastIndex' 속성을 저장한다.
- lastIndex란 다음 검색 시 검색을 시작할 인덱스를 뜻한다.
즉, g 옵션을 사용해 exec, test 등의 메소드로 일치항목을 찾을 때
--> regEx는 첫번째 일치하는 항목을 찾으면 다음 문자열의 index를 lastIndex로 저장하고
--> 다음 일치하는 항목을 찾을 수 없을 때까지 lastIndex 부터 일치 항목을 찾는다.
--> 그리고 불일치하는 항목을 찾으면 lastIndex는 0으로 재설정 된다.
이런 g 플래그의 속성 때문에 입력되는 문자열의 index가 regExp.lastIndex 보다 작으면 --> 정규식 조건과 일치해도 통과하지 않는 현상이 발생하는 것이다.
아래는 위 코드를 실행해봤을 때 나타나는 현상을 표로 정리한 것이다.
input의 currentTarget.value | 정규식 일치 여부 (숫자이면 일치) |
이후 설정되는 regExp.lastIndex |
비고 |
"1" | O | 1 | |
"1" | X | 0 | value index가 lastIndex보다 작으므로 통과하지 못함. 그리고 lastIndex는 reset됨. |
"11" | O | 1 | |
"11" | O | 2 | |
"11" | X | 0 | 위와 동일 |
"111" | O | 1 | |
"111" | O | 2 | |
"111" | O | 3 | |
"111" | X | 0 | 위와 동일 |
"1111" | O | 1 |
해결
1) regExp.lastIndex = 0으로 매번 상태를 재설정한다.
(하지만 이는 사이드이펙트 발생의 여지가 있으므로 추천하지 않는다.)
2) regExp가 매번 재선언되는 위치에 있다면 lastIndex도 재설정 되므로 위같은 오류가 발생하지 않는다.
즉, handleChange 함수 내부 혹은 컴포넌트 내부에 위치시키면 이같은 현상이 발생하지 않고, 위 코드처럼 컴포넌트 외부의 regExp를 불러오면 위 같은 현상이 발생한다.
3) g 플래그를 제거하는 방법이 있다.
전역을 검사할 필요 없이 숫자 하나라도 있으면 alert가 발동해야하는 상황 등이라면 g 플래그를 없애는 것도 방법이다.
참고 사이트
https://stackoverflow.com/questions/2630418/javascript-regex-returning-true-then-false-then-true-etc
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions
'JavaScript' 카테고리의 다른 글
Promise resolve 패턴 서치 (0) | 2021.09.28 |
---|---|
useEffect 에서 async await 호출 (0) | 2021.09.14 |
전개 구문 (Spread 연산자) (0) | 2021.05.29 |
JS | 배열 관련 메소드 (0) | 2021.01.26 |
JS | 할당 연산자 (0) | 2021.01.26 |