menulogo

[JS] keydown/keyup에서 한글 입력 시 함수가 두 번 실행되는 경우

@corinthioniaFebruary 17, 2022


MailedIt! 서비스를 개발하다 오랫동안 해결하지 못한 에러가 있었다.
Notion처럼 텍스트를 입력하고 엔터를 누르면 새로운 블럭이 만들어지는데, 기존 텍스트의 마지막 음절이 딸려오는 에러가 발생했다.


원인 분석

1. onKeyDown과 onKeyPress

구글링 해 본 결과, 단순히 onKeyDownonKeyPress로 바꾸면 해결된다고 한다.
그럼 우선 이 둘의 차이점을 알아보자.

onKeyDown: keycode 값 - 한/영, Shift, Backsapce 등 인식 가능
onKeyPress: ASCII 값 - 한/영, Shift, Backsapce 등 인식 불가

하지만 우리 프로젝트에서는 Shift 키와 Backspace 키를 인식해야 해서 onKeyPress사용할 수는 없었다.

2. KeyboardEvent.isComposing

KeyboardEvent.isComposing은 입력한 문자가 조합문자인지 아닌지를 판단한다. 한글은 자음과 모음의 조합으로 한 음절이 만들어지기 때문에 조합문자이고, 영어는 조합문자가 아니다.

한글을 입력할 때 자세히 보면 입력 중인 글자 바로 아래에 검은 밑줄이 생기는 경우가 있는데, 이 밑줄이 보이는 상황에서 Enter키를 입력하면 이벤트가 2번 발생하는 이슈가 있다. 왜냐하면 글자가 조합 중인 건지, 조합이 끝난 상태인지 파악하기가 어렵기 때문이다.

그래서 이 이슈는 영어를 입력할 때에는 발생하지 않고, 한글을 입력할 때에만 발생한다 ㅠㅠ!


해결 과정

1. 프로젝트 로직 설명

  • Enter 키 입력 시 블럭 생성
  • Shift + Enter 키 입력 시 블럭 내에서 줄바꿈
  • Backspace키가 입력되고, 블럭 안의 텍스트가 없거나 공백 문자만 있다면 블럭 삭제

내가 작성한 코드는 아니지만,, 이전에 작성했던 코드는 다음과 같다.

onKeyDownHandler(e) {
    if (e.key === 'Enter') {
      if (this.state.previousKey !== 'Shift') {
        e.preventDefault();
        this.props.addBlock({ 새로운 블럭 추가 (코드 생략) });
      }
    } else if (
      e.key === 'Backspace' &&
      (this.state.html === '' || this.state.html === '<br>')
    ) {
      e.preventDefault();
      this.props.deleteBlock({ 블럭 삭제 (코드 생략) });
    }
    this.setState({ previousKey: e.key });
  }

2. onKeyDown을 onKeyPress로 바꿔 보기

이렇게 하면 Shift 키와 Delete 키를 인식하지 못해서 줄바꿈과 블럭 삭제가 안 되는 문제가 발생했다. 우리는 저 두 가지 키를 꼭 인식해야 하므로... onKeyDown을 사용하며 해결할 방법을 모색했다.


3. event.nativeEvent.isComposing === false 추가하기

onKeyDownHandler(e) {
    if (e.key === "Enter") {
      if (
        e.nativeEvent.isComposing === false &&
        this.state.previousKey !== "Shift"
      ) {
        e.preventDefault();
        this.props.addBlock({ 새로운 블럭 추가 (코드 생략) });
      }
    }

조건식에 e.nativeEvent.isComposing === false 을 추가했다.


콘솔에서 e.nativeEvent.isComposing 값을 확인해 보면, 첫 글자를 입력할 때와 공백을 입력할 때 false 값이 찍히고, 글자를 입력하는 동안에는 true, 마지막에 Enter 키를 누르면 truefalse함께 찍히게 된다.

따라서 이전에 입력한 키가 Shift 키가 아니고, Enter를 입력했을 때 e.nativeEvent.isComposing 값이 false이면 블럭을 추가하도록 구현하여 마지막 음절이 딸려오는 에러를 해결할 수 있었다!

← 이전 글MadiledIt! 개발 회고 (Short)
다음 글 →IT 연합 동아리 DND 8기 활동 후기