[React + TypeScript] 한글 입력시 onKeyDown 이벤트 중복 발생 현상
에러 상황
OpenFace를 사용한 얼굴 인식 기반 출입 관리 시스템 프로젝트 개발 중 부서 등록 기능을 개발하면서 생긴 에러이다.
텍스트 필드에 등록할 부서 이름을 작성하고 엔터를 누르면 아래에 등록할 부서 리스트가 뜨도록 개발하고자 했다.
하지만 위 사진처럼 한글을 입력했을 때 이벤트가 중복으로 발생하여 "개발부서"를 입력하면 "개발부서"와 "서" 두 개가 입력되었다.
처음엔 비동기 처리로 인한 문제 때문인가 생각했는데 영어와 숫자는 이벤트가 한 번만 발생하는 것을 보고 한글과 관련이 있을 것이라고 생각했다.
문제 원인
원인은 IME composition 때문이었다.
IME composition란?
IME는 영어가 아닌 한글, 일본어, 중국어와 같은 언어를 다양한 브라우저에서 지원하도록 언어를 변환시켜주기 위한 OS 단계의 어플리케이션을 말한다.
한글을 입력할 때는 한 글자를 완성하기 위해 여러 번의 키 입력이 필요하다. 예를 들어, "한"이라는 글자를 입력하려면 "ㅎ", "ㅏ", "ㄴ" 세 개의 키 입력이 필요하다. 이러한 특성 때문에 한글 입력 시에는 IME(Input Method Editor)가 동작하여 자음과 모음의 조합이 이루어지는 과정을 거친다.
이 과정에서 이벤트 핸들러인 onKeyDown 이벤트는 한글 입력 시에도 자음이나 모음의 입력 과정에서 각각의 키 입력에 대해 이벤트를 발생시킨다. isComposing 속성은 이러한 IME가 입력 중인지를 나타내는 값으로, 한글 입력 시에는 true로 설정된다.
따라서 한글 입력 시에는 자음과 모음의 조합으로 이루어지는 한 글자를 완성하기 전까지 isComposing 속성이 true로 설정되어 IME가 입력 중임을 나타낸다. 한 글자가 완성되면 IME가 종료되고 isComposing 속성이 false로 설정된다.
이러한 상황에서 onKeyDown 이벤트는 조합 문자인 상태로 한 번, 해지된 상태에서 또 한 번으로 이벤트가 두 번 발생한다. 이러한 문제는 KeyboardEvent.nativeEvent.isComposing가 false인 상태에서 이벤트를 수행할 수 있도록 처리함으로써 해결할 수 있다.
해결 방법
isComposing 반환값을 이용하여 반환값에 따라 이벤트를 한 번만 수행하도록 조건을 걸어준다.
const onCheckEnter = (e:React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && !e.nativeEvent.isComposing) {
if (department.length < 1) {
if(inputRef.current !== null) {
inputRef.current.focus();
}
return;
}
setDepartmentList([...departmentList, department]);
setDepartment("");
(inputRef.current as HTMLInputElement).value = "";
}
}
- e.key가 "Enter"이고 e.nativeEvent.isComposing이 false일 때만 동작하도록 코드를 수정하였다.