<textarea />를 활용한 채팅 입력창에서 한글 Enter 키 입력 시 메시지가 두 번 전송되는 이유
🧪 코드 및 현상 재현
처음에는 아래와 같은 로직으로 채팅 입력창을 구현했습니다.
사용자가 <textarea />에 메시지를 입력한 뒤 Enter 키를 누르면, 메시지를 전송하고 입력창을 초기화하는 구조입니다.
ts
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault(); // 줄바꿈 방지
sendMessage(inputValue);
setInputValue('');
}
};한글로 "안녕하세요"를 입력하고 Enter를 누르면,
- 메시지가 두 번 전송되거나
- 마지막 글자인 "요"만 따로 전송되는 등 이상한 동작이 나타났습니다.
처음에는 handleSend() 함수가 두 번 호출되는 문제라고 생각했지만, 자세히 들여다보니 문제의 원인은 React 코드 내부가 아닌 브라우저의 한글 입력 처리 방식, IME(Input Method Editor)에 있었습니다.
🤔 왜 이런 현상이 발생할까?
이 문제의 원인은 한글 입력 방식(IME)에 있습니다.
IME(Input Method Editor)란?
한글, 일본어, 중국어 등 조합형 문자를 입력할 때 사용되는 입력기입니다.
예: 키보드로 ㅇ, ㅏ, ㄴ을 입력하면 브라우저는 안이라는 글자를 조합해서 보여줍니다.
이 과정에서 브라우저는 compositionstart, compositionend, 그리고 Enter와 같은 키 이벤트를 여러 번 발생시킵니다.
문제의 핵심
- 사용자가 한글을 조합한 뒤 Enter를 누르면:
- 조합을 확정하는 Enter 이벤트가 먼저 발생하고
- 이어서 실제 Enter 입력 이벤트가 한 번 더 발생합니다.
즉, handleKeyDown이 두 번 호출되어 메시지를 두 번 보내게 되는 것입니다.
✅ 해결 방법 isComposing 체크하기
React의 KeyboardEvent 객체는 e.nativeEvent.isComposing이라는 속성을 제공합니다.
이 값이 true이면 현재 IME 조합 중이라는 의미이므로, 이때는 Enter를 무시해 주면 됩니다.
🔧 수정된 코드
ts
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
if (e.nativeEvent.isComposing) return; // 한글 조합 중이면 무시
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};이제 한글 입력 중 Enter를 눌러도, 메시지가 한 번만 전송됩니다.
- #enter 키 입력 시 두번 실행
- #IME
- #Input Method Editor
- #textarea