크롬 브라우저에서 한글 입력시 버그와 isComposing 속성

트러블슈팅 · 2025. 3. 27.

문제상황

input(또는 textarea)에서 Enter 키를 눌러 메세지를 보내는 코드를 작성했습니다. 그런데 한글을 입력하고 Enter를 누르면 마지막 글자가 남는 버그가 발생했습니다. 그런데, 기묘하게도 영어나 숫자를 입력했을 때는 이러한 버그가 발생하지 않았고, 제출 버튼을 눌러서 제출했을때도 버그가 발생하지 않았습니다. 따라서, 한글입력과 키보드 이벤트와 관련한 이슈로 파악할 수 있었습니다.

또한 이러한 이슈는 크롬 브라우저를 사용중인 경우에만 발생하였습니다.

구글 검색을 통해 관련 이슈를 찾을 수 있었습니다.

코드 수정

수정전

const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      onSubmit(e as any);
  }
};

const submitForm = () => {
    handleSubmit();
    setInput("");
}

수정후

const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposin) {
      e.preventDefault();
      onSubmit(e as any);
  }
};

const submitForm = () => {
    handleSubmit();
    setInput("");
}

KeyboardEventisComposing 속성이 false인 경우에만 제출하도록 코드를 수정하여 버그를 수정했습니다.

IME와 isComposing

한 문자가 한 글자인 라틴 알파벳과는 달리, 한 글자가 여러 문자의 조합이나 변환을 거쳐 입력하는 문자들이 있습니다. 대표적으로는, 한글, 가나, 한자 등이 있습니다. 이러한 키 입력을 사용자가 원하는 글자와 기호로 변환하는 기술을 IME(Input Method Editor, 입력기)라고 합니다.

예를 들어, 한글로 '대한민국'을 입력하려면 'ㄷ → ㅐ → ㅎ → ㅏ → ㄴ → ㅁ → ㅣ → ㄴ → ㄱ → ㅜ → ㄱ' 순서로 키를 눌러야 합니다. IME가 없다면 이 키 입력들을 '대한민국'이라는 단어로 조합할 수 없습니다. 하지만 IME는 한글 자모로 조합되어 만들어진 글자 데이터를 기반으로 'ㄷㅐㅎㅏㄴㅁㅣㄴㄱㅜㄱ'을 '대한민국'으로 모아줍니다.

이때 조합중에는 compositionupdate 이벤트가 호출되고 조합완료시 compositionend 이벤트가 호출됩니다. KeyboardEvent 인터페이스는 isComposing이라는 속성을 제공하여 조합중인지 아닌지를 확인할 수 있습니다..

리액트의 합성 이벤트(SyntheticEvent)

리액트는 모든 브라우저에서 이벤트를 동일하게 처리하기 위해서 SyntheticEvent 객체를 전달받습니다. 브라우저마다 이벤트 처리방식이 상이하기도 함 따라서 합성 이벤트를 사용해여 크로싱 브라우저 이슈를 해결하고 개발 경험을 향상함. 만약 브라우저의 고유 이벤트에 접근하기 위해서는 nativeEvent 속성을 를 참고해야합니다.

interface SyntheticEvent<T = Element, E = Event>
  extends BaseSyntheticEvent<E, EventTarget & T, EventTarget> {}

interface BaseSyntheticEvent<E = object, C = any, T = any> {
  nativeEvent: E;
  currentTarget: C;
  target: T;
  bubbles: boolean;
  cancelable: boolean;
  defaultPrevented: boolean;
  eventPhase: number;
  isTrusted: boolean;
  preventDefault(): void;
  isDefaultPrevented(): boolean;
  stopPropagation(): void;
  isPropagationStopped(): boolean;
  persist(): void;
  timeStamp: number;
  type: string;
}

문제의 원인과 해결방법

크롬 브라우저에서는 한글 입력 시 입력 중인 글자 아래 검은 밑줄이 있는 상황에서 키보드 이벤트 발생시 이벤트 핸들러가 두 번 호출된다. 이때 첫번째 이벤트에서는 isComposingtrue이고 두번째 이벤트에서는 false입니다. (event.currentTarget.value 값은 각각 “안녕하세요”“요”) 만약 오른쪽 방향키 등을 통해 검은 밑줄을 없애면 isComposingfalse로 한번만 호출됩니다.

파이어폭스에서는 isCompsingfalse로 한번만 호출됩니다.

문제의 원인은 각 이벤트의 발동 순서와 관련있는 것으로 추정됩니다. isComposingtrue인 경우 input의 값이 리액트 상태에 반영되기 이전에 초기화가 진행되어 초기화가 제대로 진행되지 않아 해당 버그가 발생한 것 같습니다.

크롬 브라우저
1. beforeinput
2. (compositionupdate)
3. input
4. compositionend
5. (no input)

파이어폭스와 엣지
1. (beforeinput not yet supported on them)
2. (compositionupdate)
3. (no input)
4. compositionend
5. input
// 출처 : https://github.com/w3c/uievents/issues/202