React, 한글 입력시 keydown 이벤트 중복 발생 현상

글을 작성한 이유

회사에서 autoComplete 컴포넌트를 만드는 과정에서 방향키를 이용해 자동완성 검색어를 탐색할 수 있도록 keydown 이벤트 핸들러를 등록한 적이 있다. 이 때, 영어가 아닌 한글로 입력한 후 keydown 이벤트를 실행할 때 이벤트가 중복으로 발생하였다. 문제의 원인을 찾고 이를 해결하는 과정을 공유하고자 한다.

문제 원인

IME composition

IME는 영어가 아닌 한글, 일본어, 중국어와 같은 언어를 다양한 브라우저에서 지원하도록 언어를 변환시켜주기 위한 OS 단계의 어플리케이션을 말한다.

그러나 IME 과정에서 keydown 이벤트가 발생하면, OS와 브라우저에서 해당 이벤트를 모두 처리하기 때문에 keydown 이벤트가 중복으로 발생하게 되는 것이다.

즉, IME를 통해 한글, 일본어, 중국어 등을 변환하는 과정(composition)에서 keydown 이벤트는 OS 뿐만 아니라 브라우저에서도 처리되기 때문에 중복 발생된다.

isComposing

이를 위해 Web API 스펙을 확인하며 event target에 KeyboardEvent.isComposing 이라는 프로퍼티를 제공한다. 자세한 설명을 보면, composition Session 중에 event가 발생하는지 여부를 불리언 값으로 반환한다고 명시되어 있다 (The KeyboardEvent.isComposing read-only property returns a boolean value indicating if the event is fired within a composition session)

즉, 한글 등 비영어권 언어를 표현하는 과정에서 이 값을 참조하면 true값을 반환한다.

해결 전략

isComposing 때 return

const keyboardEventHandler = (event) => {
 if(event.isComposing) return; 
  
  // ... 나머지 키보드 이벤트 
}

isComposing이 참인 순간은 아직 IME에 의한 composition 단계이므로, 이 단계에서 이벤트가 발생하지 않도록 하는 방법을 사용할 수 있다.

keycode 를 이용하는 방법도 있지만, keycode 는 deprecated 되었다고 하므로 사용을 지양하는 것이 좋겠다.

React 에서 해결 방법

isComposing 이 없는데...

하지만 리액트에서 keyboard event 객체를 살펴보면, isComposing이라는 프로퍼티를 제공하지 않는다. 방법을 찾다가, 아까 web API 문서에서 Composition Sesseion 다음에 이런 말이 나온다.

after compositionstart and before compositionend.

이 말을 즉, compoistion 단계의 시작과 끝을 위한 이벤트가 별도로 존재한다는 말이다. 찾아보니 react에서 composition event를 별도로 제공한다. (리액트 컴포지션 이벤트 )

onCompositionStart, onCompositionEnd

const [isComposing, setIsComposing] = useState(false); 
const handleClickEvent = (event) => {
  if(isComposing) return; 
  
  // 키보드 이벤트 ..
}

<AutoComplete
	onCompositionStart={()=>setIsComposing(true)}
    onCompositionEnd={()=>setIsComposing(false)}
    onKeydown={hanleClickEvent}
/>

이런 식으로 isComposing 상태를 별도로 관리하여, 각각의 composition 이벤트가 발생할 때 상태의 값을 변경하면 한글 입력에 따른 keydown 이벤트의 중복을 막을 수 있다.

좋은 웹페이지 즐겨찾기