한글 입력시 api 호출이 두 번 되길래
엥 이거 왜이래!
하고 서치해보다 알게 된 것들을 정리해보려 한다.
(대부분 keydown에 관한 해결책이었어서 keyup을 쓰고 싶은 누군가에게 도움이 되었으면...)
가보자고~
일단 이미지에서 보이는 것 처럼
Input에 한글을 입력하고 엔터를 하면
onEnter에 걸려있는 api 호출 이벤트가 두 번 발생하는 문제가 있었다.
※ 참고
Input
이라는 공통 컴포넌트를 사용 중Input
에 onEnter
로 이벤트를 넘겨주면,onKeyup
에서 e === "Enter"
일 때 실행'const keyupCallback = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && is_composed) {
onEnter && onEnter(e.key)
}
onKey && onKey(e)
},
[onEnter, onKey],
)
// 중략
<input
// ...props
onKeyup={keyupCallback}
/>
이건 IME라는 녀석 때문에 발생하는 문제다.
영어나 숫자와는 달리, 한국어는
ㅇ + ㅏ + ㄱ 이 '악'가 되어 한 글자가 되는 과정이 필요한데
브라우저도, IME도 두개 다 이걸 처리하느라 이벤트가 두 번 호출 되는 것이라고 한다.
의도적으로 일정 시간 내에 발생하는 이벤트를 무시하는 방법이다.
const debounceSearchEvent = useDebounce((name: string) => {
search(name)
}, 100)
기존 만들어두었던 useDebounce 훅을 활용해 구현했던 코드인데,
각 인터넷 속도나 사용 상황차이가 있을 수 있어
결국 두 번 호출 되는 문제를 근본적으로 막지는 못하는 코드라 생각된다.
관련 내용을 서치하다보면 가장 많이 뜨는 내용이다.
if e.nativeEvent.isComosing === true return;
changeEvent 등에서는 위 한 줄로 대부분을 막을 수 있겠지만..
이상하게 내 케이스에는 적용이 안됐다.
그래서 고전하고 있던 차에 사수분이 찾아준 자료.
(이미지 출처: https://w3c.github.io/uievents/#events-composition-key-events)
보면 keydown -> composition -> keyup 의 순서를 거치고 있다.
그리고 한글 입력 후 엔터를 눌렀을 때는?
keydown -> composition -> keyup
keydown -> keyup
의 두가지 이벤트가 순서대로 일어났다.
그러니 isComposing으로 아무리 막아봐라... keyup에 걸린 이벤트는 싹 무시하고 일어나지...
따라서 composition 단계를 거치는 enter이벤트는 무시하게끔
is_composed라는 값을 추가했다 (true면 composition 단계를 거친 거니 무시!)
let is_composed
onKeydown => is_composed = true
onCompositionEnd => is_composed = false
그리고 이렇게 composition 단계를 잘 신경써주면...!
(급하게 쓰느라 글의 퀄리티는 안 성공)