OTTER-LOG

onkeyup, onkeydown과 button

onkeyup, onkeydown과 button
by otter2022년 12월 28일에 최종수정되었습니다.
잘못된 내용이 있으면 댓글을 달아주세요.

상황

Trigger 컴포넌트는 기본적으로 button 태그를 이용합니다. 그런데, 저희의 프로젝트 특성 상 어떠한 태그로 변경해도 괜찮을 수 있도록 컴포넌트를 만들고 있었는데 이 경우에 button 태그가 기본적으로 가지고 있는 키보드 이벤트를 막아야 했습니다. - 이를 이용할 시, 태그를 임의적으로 div, sapn 등으로 변경할 때에 이벤트가 원활히 작동되지 않을 것이라 생각했기 때문입니다. -

(keyPress 의 경우 Deprecated 되어 사용하지 않았습니다. )

// Trigger ... const handleClick = (e: React.MouseEvent) => { setIsOpen(!isOpen); console.log("handle click 실행됨"); // 클릭을 할때에, 이 함수가 실행됩니다. }; const handleKeyup = (e: React.KeyboardEvent) => { if (e.key === "Enter") { e.preventDefault(); } if (e.key === " ") { e.preventDefault(); } // 이런 방식으로 기본적으로 가지고 있는 이벤트를 막을 수 있다고 생각했습니다. }; return ( <button onClick={handleClick} ref={mergeRefs([triggerRef, forwardRef])} id={labelRef.current?.id} role='combobox' aria-controls={optionsRef.current?.id} aria-expanded={isOpen} aria-labelledby={labelRef.current?.id ?? labelledby} aria-haspopup='listbox' className={className} onKeyUp={handleKeyup} // 일반적으로 onKeyUp을 아무 생각 없이 사용해왔었기에, // onKeyUp으로 해당 핸들러를 적용해 주었습니다. tabIndex={0} > {selectedValue ?? placeHolder} {children} </button> );

위와 같이 e.preventDefault() 를 통해 기본적으로 작동하는 동작을 막을 수 있을 것이라 생각했는데, onKeyUp 으로 이벤트 핸들러를 등록하면 onClick 에 등록되어져 있는 핸들러 함수가 작동되었습니다.

버튼에 포커스를 두고, Enter 를 하게 되면 아래와 같이 handleClick 함수가 실행되었습니다.

사실 위와 같은 부분은 버튼의 기본적인 이벤트이므로, Enter 를 했을 때에 자동적으로 버튼이 클릭되는 것처럼 동작하는 것으로 당연한 결과였습니다.

그런데, 이를 keyDown 으로 변경하면 의도한 바대로 이벤트의 동작이 잘 막아집니다.

const handleClick = (e: React.MouseEvent) => { setIsOpen(!isOpen); console.log("handle click 실행됨"); }; const handleKeyup = (e: React.KeyboardEvent) => { console.log('keydown 실행됨') if (e.key === "Enter") { e.preventDefault(); } if (e.key === " ") { e.preventDefault(); } }; return ( <button onClick={handleClick} ref={mergeRefs([triggerRef, forwardRef])} id={labelRef.current?.id} role='combobox' aria-controls={optionsRef.current?.id} aria-expanded={isOpen} aria-labelledby={labelRef.current?.id ?? labelledby} aria-haspopup='listbox' className={className} onKeyDown={handleKeyup} // 이 부분만 onKeyDown으로 바꿔주었습니다. tabIndex={0} > {selectedValue ?? placeHolder} {children} </button> ); }, );

왜 이런 방식이 가능한걸까요? 사실 지금까지는 아무 생각 없이 onClick, onKeyUp 을 기반으로 사용하고 있었습니다. 둘의 무슨 차이점이 있었기에, onKeyDown 을 사용하게 되면 onClick 이 일어나는 것을 막을 수 있었던 것일까요?


keyUp, keyDown 의 차이점

기본적으로 onKeyUp, onKeyDown의 차이점은 다음과 같습니다.

  • onKeyUp

    유저가 키보드에서, 버튼을 release 했을때에 이벤트가 실행됩니다.

    이벤트는 한번만 실행됩니다.

  • onKeyDown

    유저가 키보드에서, 버튼을 press 했을때에 이벤트가 실행됩니다.

    버튼을 계속 누르고 있다면, 이벤트는 계속해서 실행됩니다.

이를, 마우스 이벤트와 연관지어 보겠습니다.

  • onMouseDown

    유저가 마우스 버튼을 눌렀을때 이벤트가 실행욉니다.

  • onMouseUp

    유저가 마우스 버튼을 뗐을때에 이벤트가 실행됩니다.

→ 사실 위 두가지 요소는, 지금과 관련은 없지만 간단히 정리했습니다.

  • onClick

    유저가 마우스 버튼을 눌렀다 땠을 때에 이벤트가 실행됩니다.

    onMouseDown, onMouseUp 의 조합으로 이루어져 있습니다.

여기서, button 이라는 태그는 기본적으로 가지고 있는 동작은 onClick 입니다. 이때 Enter 키보드 이벤트는 onClick 을 실행합니다. 그런데, onClick 은 사용자가 마우스로 버튼을 눌렀을때 (enter를 했을때) 와 떼었을 때 모두 실행됩니다.

따라서, onKeyUpe.preventDefault() 를 한다고 해도 onClick 이벤트기 살행됩니다. onKeyUp 이 실행되는 시점은 onKeyDown 다음인데, onKeyDown 이 이루어진 시점에 onClick 이 이를 감지에 실행되었기 때문입니다.

위와 같은 이유로, button 의 기본적인 enter 이벤트를 막기 위해서는 onKeyDown 을 막아야 합니다!