에러 상황
- 진행 중인 프로젝트에서 input 태그에 텍스트를 입력 후, 엔터키를 누를 시 목록에 입력한 텍스트가 추가되는 기능을 개발 중이였다.
- 영어 텍스트를 입력 시에는 문제가 없었지만, 한글 텍스트를 입력하는 경우에 해당 문제가 발생되어 원인을 검색해보았다.
/** 입력 중 엔터키 누를 시 할일이 추가되는 함수 */
const handlePressEnter = (event: React.KeyboardEvent) => {
if (event.key === "Enter") {
if (toDoList.map((todo) => todo.name).includes(typedTodo)) {
alert("중복된 할일이 존재합니다.");
return;
}
handleAddTodo(id, { name: typedTodo });
setTypedTodo("");
}
};
원인
- 일반 키보드에서 쉽게 입력될 수 없는 언어로 텍스트를 입력할 수 있는 OS 레벨의 입력 에디터
- 한글을 입력 시, 한글의 어휘는 자음+모음 및 받침으로 구성이 되기 때문에, IME가 해당 구성요소들을 하나의 글자로 합성(Composition)하는 것을 도와준다.
ex)
- "리엑트"라는 글자가 있다고 가정하자.
- "리엑트"라는 글자를 입력하고 엔터를 눌렀을 때, "리엑"은 입력 및 합성(Composition)이 완료되었지만, "트"는 합성이 완료되지 않았을(Composing) 수 있다. 이때 "리엑트" 와 "트" 총 두 번의 이벤트 핸들러가 동작하게 되는 흐름이다.
버튼 클릭 vs 엔터키
- 버튼 클릭 시에는 IME가 입력한 글자를 이미 완성된 상태로 간주(마우스 클릭 이벤트는 IME와 관련없이 동작)한다. 즉 모든 글자의 합성이 완료되어 중복 입력 이슈가 발생되지 않는다.
- 엔터키를 누를 경우 텍스트를 입력 한 후 엔터를 누를 시, IME가 아직 합성 중인 글자가 있다고 판단하게 된다. 따라서 합성이 완료된 글자에 대한 이벤트("리엑트")와 합성 중인 글자에 대한 이벤트("트"), 이렇게 두 번의 중복 이벤트가 발생하게 된다.
해결
- 아래와 같이 Composing(합성중)일 때는 이벤트 핸들러가 동작하지 않도록 하여 해결하였다.
/** 입력 중 엔터키 누를 시 할일이 추가되는 함수 */
const handlePressEnter = (event: React.KeyboardEvent) => {
if (event.nativeEvent.isComposing) {
return;
}
if (event.key === "Enter") {
if (toDoList.map((todo) => todo.name).includes(typedTodo)) {
alert("중복된 할일이 존재합니다.");
return;
}
handleAddTodo(id, { name: typedTodo });
setTypedTodo("");
}
};