새로운 블로그로 이전했습니다!
https://corinthionia.github.io/post/javascript/keydown-keyup-twice
MailedIt! 서비스를 개발하다 오랫동안 해결하지 못한 에러가 있었다.
Notion처럼 텍스트를 입력하고 엔터를 누르면 새로운 블럭이 만들어지는데, 기존 텍스트의 마지막 음절이 딸려오는 에러가 발생했다.
구글링 해 본 결과, 단순히 onKeyDown
을 onKeyPress
로 바꾸면 해결된다고 한다.
그럼 우선 이 둘의 차이점을 알아보자.
onKeyDown: keycode 값 - 한/영, Shift, Backsapce 등 인식 가능
onKeyPress: ASCII 값 - 한/영, Shift, Backsapce 등 인식 불가
하지만 우리 프로젝트에서는 Shift
키와 Backspace
키를 인식해야 해서 onKeyPress
를 사용할 수는 없었다.
KeyboardEvent.isComposing
은 입력한 문자가 조합문자인지 아닌지를 판단한다. 한글은 자음과 모음의 조합으로 한 음절이 만들어지기 때문에 조합문자이고, 영어는 조합문자가 아니다.
한글을 입력할 때 자세히 보면 입력 중인 글자 바로 아래에 검은 밑줄이 생기는 경우가 있는데, 이 밑줄이 보이는 상황에서 Enter
키를 입력하면 이벤트가 2번 발생하는 이슈가 있다. 왜냐하면 글자가 조합 중인 건지, 조합이 끝난 상태인지 파악하기가 어렵기 때문이다.
그래서 이 이슈는 영어를 입력할 때에는 발생하지 않고, 한글을 입력할 때에만 발생한다 ㅠㅠ!
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 });
}
이렇게 하면 Shift
키와 Delete
키를 인식하지 못해서 줄바꿈과 블럭 삭제가 안 되는 문제가 발생했다. 우리는 저 두 가지 키를 꼭 인식해야 하므로... onKeyDown
을 사용하며 해결할 방법을 모색했다.
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
키를 누르면 true
와 false
가 함께 찍히게 된다.
따라서 이전에 입력한 키가 Shift
키가 아니고, Enter
를 입력했을 때 e.nativeEvent.isComposing
값이 false
이면 블럭을 추가하도록 구현하여 마지막 음절이 딸려오는 에러를 해결할 수 있었다!
입출력이 제일 쉬운 것 같으면서도 버그를 야기하는 상황이 많은 것 같아요😥