Korean KeyboardEvent Error in React
0. 들어가면서
리액트(react) 프로젝트에서 한글을 입력할 때 마지막 문자가 중복으로 입력되는 현상을 발견하였습니다. 한글 입력 시 발생하는 문제점과 원인, 해결 방법에 대해 정리하였습니다.
1. 문제 현상
1.1. 문제 코드
아래 코드를 크롬 브라우저에서 실행하면 한글을 입력할 때 문제가 발생합니다.
- 텍스트 박스(text box)에 한글을 입력하고 엔터(enter)를 누릅니다.
- 입력된 값을 저장하고 텍스트 박스의 값은 초기화합니다.
- 입력된 값의 마지막 문자가 추가로 저장됩니다.
import React, { ChangeEvent, KeyboardEvent, useState } from "react";
import "./App.css";
function App() {
const [todo, setTodo] = useState<string>("");
const [todoList, addTodoList] = useState<string[]>([]);
const onChangeHandler = (event: ChangeEvent<HTMLInputElement>) => {
setTodo(event.target.value);
};
const onKeyboardEvent = (event: KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Enter") {
addTodoList((prevState) => {
return [...prevState, todo];
});
setTodo("");
}
};
return (
<div className="App">
<input
type="text"
value={todo}
onChange={onChangeHandler}
onKeyDown={onKeyboardEvent}
/>
<div>
{todoList.map((todo, index) => (
<div key={index} className="todo">
{todo}
</div>
))}
</div>
</div>
);
}
export default App;
실행 결과
2. IME(Input Method Editor)
Error on v-model with Korean in Vue 포스트에서 다뤘던 개념입니다.
이 문제는 IME(Input Method Editor) 과정에서 KeyDown
이벤트가 발생할 때 운영체제와 브라우저가 해당 이벤트를 중복 처리하기 때문에 발생합니다.
위키피디아(wikipedia)에선 IME를 다음과 같이 정의합니다.
IME(Input Method Editor)
An input method (or input method editor, commonly abbreviated IME) is an operating system component or program that enables users to generate characters not natively available on their input devices by using sequences of characters (or mouse operations) that are natively available on their input devices. Using an input method is usually necessary for languages that have more graphemes than there are keys on the keyboard.
IME
는 한글 같은 조합이 필요한 문자의 입력을 지원하기 위한 운영체제(operating system)의 컴포넌트(component) 혹은 프로그램입니다.
이 기능을 통해 사용자는 입력 기기를 사용해 직접 입력할 수 없는 문자들을 조합하여 작성할 수 있습니다.
예를 들면 사용자는 라틴(latin) 계열 키보드로 중국어, 일본어, 한국어 등을 입력할 수 있습니다.
한글처럼 IME 기능이 필요한 언어를 브라우저에서 입력할 땐 정상적인 처리가 안 될 수 있습니다.
문제 양상은 운영체제, 브라우저 종류마다 다를 수 있습니다.
3. 문제 해결
3.1. CompositionEvent
해결 방법은 Web API
에서 제공하는 CompositionEvent
와 관련 있습니다.
CompositionEvent
는 키보드에서 사용할 수 없는 문자를 입력 받기 위한 보조적인 방법을 제공합니다.
- US 키보드엔 존재하지 않지만, 문자에 강조(accent)를 줄 때 사용
- 아시아 언어의 기본 컴포넌트인 로고그램(logogram)들을 빌드-업(build-up)할 때 사용
문자를 합성하는 컴포지션 세션(composition session)은 compositionstart
, compositionupdate
, compositionend
이벤트로 구성됩니다.
compositionupdate
이벤트는 여러 번 발생할 수 있습니다.
각 세션 동안 이벤트 체인 각 단계 사이의 값들은 지속되며 data
속성에 유지됩니다.
브라우저는 컴포지션 세션을 통해 IME 기능을 제공합니다.
3.2. isComposing Property
키보드 이벤트를 살펴보면 isComposing
라는 속성이 존재합니다.
KeyboardEvent.isComposing
The KeyboardEvent.isComposing read-only property returns a boolean value indicating if the event is fired within a composition session, i.e. after compositionstart and before compositionend.
isComposing
속성은 컴포지션 세션이 시작될 때 true
, 세션이 종료될 때 false
상태가 됩니다.
컴포지션 세션의 상태를 확인해 키보드 이벤트를 제어하면 한글 입력 문제를 방지할 수 있습니다.
3.3. 문제 해결 코드
- 리액트 라이브러리
KeyboardEvent
이벤트 내부nativeEvent
객체의isComposing
속성을 사용합니다.- 바닐라 자바스크립트가 아니기 때문에 이벤트 객체 내부엔
isComposing
속성이 존재하지 않습니다.
- 바닐라 자바스크립트가 아니기 때문에 이벤트 객체 내부엔
isComposing
상태가true
인 경우에 키보드 이벤트를 막습니다.
import React, { ChangeEvent, KeyboardEvent, useState } from "react";
import "./App.css";
function App() {
const [todo, setTodo] = useState<string>("");
const [todoList, addTodoList] = useState<string[]>([]);
const onChangeHandler = (event: ChangeEvent<HTMLInputElement>) => {
setTodo(event.target.value);
};
const onKeyboardEvent = (event: KeyboardEvent<HTMLInputElement>) => {
if (event.nativeEvent.isComposing) {
return;
}
if (event.key === "Enter") {
addTodoList((prevState) => {
return [...prevState, todo];
});
setTodo("");
}
};
return (
<div className="App">
<input
type="text"
value={todo}
onChange={onChangeHandler}
onKeyDown={onKeyboardEvent}
/>
<div>
{todoList.map((todo, index) => (
<div key={index} className="todo">
{todo}
</div>
))}
</div>
</div>
);
}
export default App;
실행 결과
CLOSING
onKeyDown
이벤트를 onKeyPress
이벤트로 변경하면 해당 문제가 해결되지만, 다음과 같은 문제점들이 존재합니다.
- 리액트에서
onKeyPress
이벤트는 더 이상 지원하지 않습니다.(deplicated) onKeyPress
이벤트는 한/영, Shift, Backsapce 등의 키를 인식하지 못 합니다.
TEST CODE REPOSITORY
REFERENCE
- https://en.wikipedia.org/wiki/Input_method
- https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
- https://www.w3.org/TR/uievents/#keys-IME
- https://stackoverflow.com/questions/51226598/what-is-javascripts-compositionevent-please-give-examples
- https://ntalbs.github.io/2015/editor-ime/
- [JS] keydown/keyup에서 한글 입력 시 함수가 두 번 실행되는 경우
- React, 한글 입력시 keydown 이벤트 중복 발생 현상
댓글남기기