ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React.js] SyntheticEvent(합성 이벤트)
    Front-End(Web)/React - 프레임워크(React, Next) 2021. 3. 15. 06:44
    반응형

    프로젝트를 진행하며 마우스 이벤트를 정리한다는게... 이벤트 공부로 판이 커져버렸다 😀😀

    React 공식문서는 지원 이벤트를 "합성 이벤트" 개념과 함께 소개했고, 합성 이벤트를 공부하던 차에 이벤트 핸들링과 연계는 필연적이었기 때문이다.

     

    이번 포스팅은, e(합성 이벤트)에 대해 자세히 공부하고, React가 지원하는 이벤트 종류를 한번 훑어보고자 한다!

    * 포스팅 : React 이벤트 핸들링(abangpa1ace.tistory.com/128)


    📒 합성 이벤트(SyntheticEvent) 란?

    SyntheticEvent는 객체로 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 Wrapper 객체이다. 대부분의 인터페이스는 브라우저 고유 이벤트와 같다.

    * 소프트웨어에서 래핑(Wrapping) 이란, 기본기능을 감싸는 새로운 기능을 만드는 것을 의미한다.

     

    React는 Element가 처음 렌더링될 때 이벤트 리스너를 제공하여 처리한다. (JS는 초기에 addEventListener 이벤트리스너 바인딩)

    이때, 리스너와 대응되는 이벤트 핸들러 함수는 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 이벤트 래퍼를 전달받아야 하며, React 에서 제공하는 이 이벤트 래퍼가 바로 SyntheticEvent(합성 이벤트) 객체인 것이다.

     

    다시 말하면, 한 단계 래핑된 이벤트 관련 객체를 통해, 이벤트를 처리하는 것이 SyntheticEvent 객체의 주요 의의이다.

    통상, SyntheticEvent 객체는 event 혹은 e(축약형태)로 작성하고, 내부 필드를 참조한다.

     

    - SyntheticEvent 객체 필드(Attribute) 종류

    boolean bubbles
    boolean cancelable
    DOMEventTarget currentTarget
    boolean defaultPrevented
    number eventPhase
    boolean isTrusted
    DOMEvent nativeEvent
    void preventDefault()
    boolean isDefaultPrevented()
    void stopPropagation()
    boolean isPropagationStopped()
    void persist()
    DOMEventTarget target
    number timeStamp
    string type
    • bubbles : 이벤트가 DOM을 통해 상위로 전파되는지 여부를 boolean 반환한다. (이벤트 버블링 : 하위에서 상위요소로 이벤트 전파)
    • cancelable : 이벤트에 규정한 액션을 취소할 수 있는지 여부를 boolean 반환한다.
    • currentTarget : 이벤트 핸들러가 부착된 DOM 요소를 반환한다. (event.target은 이벤트가 직접 발생한 DOM, 자식이 될 수도 있음)
    • defaultPrevented : 해당 DOM의 기본 이벤트가 prevent 됬는지 여부를 반환한다. (preventDefault() 와 상관성 있음)
    • eventPhase : 이벤트 흐름의 현재 실행단계를 반환한다. (0: NONE, 1: CAPTIRING_PHASE, 2: AT_TARGET, 3: BUBBLING_PHASE)
    • isTrusted : 이벤트가 사용자 행위에 의해 발생되면 true, 스크립트로 생성/수정되거나 dispatchEvent로 보내졌으면 false
    • preventDefault() : 해당 DOM의 기본 이벤트를 막는 역할의 메서드이다. void 타입으로 반환값이 없다.
    • isDefaultPrevented() : 해당 이벤트 객체에서 preventDefault() 가 호출되었는지 여부를 반환한다.
    • stopPropagation() : 여러 중첩된 DOM의 경우, 이벤트 타겟 외 DOM에 이벤트가 적용되지 않도록 버블링을 막는 메서드이다.
    • isPropagationStopped() : 해당 이벤트 객체에서 stopPropagation() 이 호출되었는지 여부를 반환한다.
    • persist() : React v16까지 비동기 콜백함수에서 합성 이벤트 활용을 위해 사용된 메서드이다. v17부터는 풀링 최적화로 불필요해짐.
    • target : 이벤트 핸들러가 할당된 DOM에서 이벤트가 직접 발생한 DOM을 반환한다. 즉, 자식 컴포넌트가 될 수도 있음.
    • timeStamp : 이벤트가 발생했던 시간을 밀리초 단위로 반환한다.
    • type : 이벤트의 타입을 문자열로 반환한다. (click, load, error 등)

     

    - Event Pooling(풀링)

    SyntheticEvent는 Pooling 되며 성능상의 이유로 SyntheticEvent 객체는 재사용되고 모든 속성은 이벤트 핸들러가 호출된 다음 초기화됩니다. 따라서, 비동기적으로 이벤트 객체에 접근할 수 없습니다.

    * 링크 : ko.reactjs.org/docs/legacy-event-pooling.html

     

    React 공식문서의 이벤트 풀링은 다음과 같이 설명한다. 즉, 특정 이벤트가 발생하면 이벤트 로직이 아래와 같이 실행된다.

    1. SyntheticEvent Pool(합성 이벤트 풀)에서 SyntheticEvent 객체에 대한 참조를 받는다.
    2. 이벤트 정보를 SyntheticEvent 객체에 넣어준다.
    3. 유저가 지정한 이벤트 리스너 및 핸들러가 실행된다.
    4. SyntheticEvent 객체가 초기화된다.
    function handleChange(e) {
      // This won't work because the event object gets reused.
      setTimeout(() => {
        console.log(e.target.value); // Too late!
      }, 100);
    }

    즉, 이처럼 비동기적으로 SyntheticEvent 객체를 활용하게 되면, 초기화로 인해 이벤트 핸들링이 불가하다는 개념이다.

     

    이를 방지하기 위해, e.persist() 메서드를 사용하거나, 이벤트의 값들을 변수에 담는 등의 방법을 사용했다.

    // 1) event.persist()
    function handleChange(e) {
      e.persist();
      
      setTimeout(() => {
        console.log(e.target.value); 
      }, 100);
    }
    
    // 2) 변수에 저장
    function handleChange(e) {
      const { name, value } = e.target;
      
        setTimeout(() => {
        console.log(alue);
      }, 100);
    }

    하지만, React 17 버전부터는 이벤트 풀링 최적화를 지원하며, 이에 따라 비동기 로직에서도 합성 이벤트를 용이하게 다룰 수 있다.

     

    - NativeEvent (고유 이벤트)

    브라우저의 고유 이벤트를 확인하려고 한다면, event.nativeEvent attribute 를 사용하면 된다.

    다만, SyntheticEvent가 브라우저의 NativeEvent와 완벽하게 대응되는 것은 아니다.

    * 예를 들어, onMouseLeave 의 event.nativeEvent 는 mouseout 이벤트를 가리킨다.


    📒 React 지원 이벤트

    드디어! 내가 한번 훑고 싶었던 React 이벤트 종류들이다. 이 이벤트 리스너들은 모두 버블링 단계에서 호출된다.  

     

    1) Clipboard 이벤트 : 클립보드에 컨텐츠 잘라내기, 복사, 붙여넣기 등 이벤트에 대한 리스너

    • onCopy
    • onCut
    • onPaste

    * 속성

    DOMDataTransfer clipboardData

     

    2) Composition 이벤트 : 이벤트 Composition System의 각 시점에 대한 리스너. 

    • onCompositionStart
    • onCompositionUpdate
    • onCompositionEnd

    * 속성

    string data

     

    * 예시

    class CompositionEvent extends React.Component {
        state={
              textData: ''
        };
    
        onChange = (e) => {
          console.log('onChange: ' + e.target.value);
          this.setState({
          	[e.target.name]: e.target.value
          });
        };
    
        onKeyDown = (e) => {
          console.log('onKeyDown: ' + e.key);
        };
    
        onCompositionStart = (e) => {
            console.log('onCompositionStart: ' + e.data);
        };
    
        onCompositionUpdate = (e) => {
            console.log('onCompositionUpdate: ' + e.data);
        };
    
        onCompositionEnd = (e) => {
            console.log('onCompositionEnd: ' + e.data);
        };
    
        render() {
            return (
                <div>
                    <h1>Event Practice</h1>   
                    <input
                        type ="text"
                        name="textData"
                        placeholder="text input..."
                        value={this.state.textData}
                        onChange={this.onChange}
                        onKeyDown={this.onKeyDown}
                        onCompositionStart={this.onCompositionStart}
                        onCompositionUpdate={this.onCompositionUpdate}
                        onCompositionEnd={this.onCompositionEnd}
                    />  
                </div>
            );
        }
    
    }

     

    <input> 태그에서, text composition system 이다.

     

    onKeyDown -> onCompositionStart -> onCompositionUpdate -> onChange -> onCompositionEnd 

    순으로 이벤트가 발생한 것을 알 수 있다.

     

     

     

     

     

     

    3) keyboard 이벤트

    • onKeyDown : 키를 눌렀을 때 이벤트다. 값 입력전에 발생하며, shift, alt, ctrl 등 특수키에 동작한다. (한/영, 한자 등은 인식불가)
    • onKeyUp : 키를 눌렀다 땠을 때 이벤트다. 값 입력후에 발생하며, onKeyDown 과 동일하게 동작한다.
    • onKeyPress : 키가 눌러져있을 때 이벤트이다. 실제 글자가 작성될때 이벤트이며, ASCII 값으로 사용되어 특수키를 인식 못한다.

    * 속성

    boolean altKey
    number charCode
    boolean ctrlKey
    boolean getModifierState(key)
    string key
    number keyCode
    string locale
    number location
    boolean metaKey
    boolean repeat
    boolean shiftKey
    number which

     

    4) Focus 이벤트 : 포커스는 <form> 뿐만 아니라, 모든 React DOM 요소에서 작동한다.

    • onFocus : 요소(또는 자식요소) 가 포커스될 때 호출된다.
    • onBlur : 요소(또는 자식요소) 가 포커스가 사라졌을 때 호출된다.

    * 속성

    DOMEventTarget relatedTarget

     

    5) Form 이벤트 : <form> 태그의 주요 기능들에 대한 이벤트 리스너

    • onChange
    • onInput
    • onInvalid
    • onReset
    • onSubmit

     

    6) Generic 이벤트 : 말 그대로 포괄적인 이벤트에 대한 리스너이다. 로드 혹은 에러 발생시 핸들러를 지정할 때 사용된다.

    • onError
    • onLoad

     

    7) Mouse 이벤트 : 오늘 포스팅의 주목적이다. 많은 종류가 있고, 그만큼 각각의 차이를 아는게 중요할 것 같다.

    • Click 이벤트
      • onMouseDown : 마우스 버튼이 클릭되기 시작할 때 (왼쪽, 오른쪽 모두 해당)
      • onMouseUp : 마우스 버튼이 클릭이 끝날 때 (왼쪽, 오른쪽 모두 해당)
      • onClick : 마우스 왼쪽버튼 클릭
      • onDoubleClick : 마우스 왼쪽버튼 더블클릭
      • onContextMenu : 마우스 오른쪽버튼 클릭
    • Drag 이벤트
      • onDragStart : 드래그 시작할 때
      • onDrag : 드래그 될 때
      • onDragEnd : 드래그가 끝날 때
      • onDragExit : 드래그된 요소가 더 이상 드래그의 직접적인 대상이 아니게 된 경우
    • Drop 이벤트
      • onDragEnter : 드래그된 요소가 드롭 대상에 들어갈 때 
      • onDragOver : 드래그된 요소가 드롭 대상 위에 있을 때
      • onDragLeave : 드래그된 요소가 드롭 대상을 떠날 때
      • onDrop : 드래그 된 요소가 드롭 대상에 떨어질 때
    • Hover 이벤트
      • onMouseOver : 마우스 포인터가 대상요소에 들어올 때. (자식요소까지 포함된다)
      • onMouseMove : 마우스 포인터가 대상요소 내에 있을 때
      • onMouseOut : 마우스 포인터가 대상요소를 벗어날 때. (자식요소까지 포함된다)
      • onMouseEnter : 마우스 포인터가 바인딩된 요소에 들어올 때. (자식요소 미포함)
      • onMouseLeave : 마우스 포인터가 바인딩된 요소를 벗어날 때. (자식요소 미포함)

    * 속성

    boolean altKey
    number button
    number buttons
    number clientX
    number clientY
    boolean ctrlKey
    boolean getModifierState(key)
    boolean metaKey
    number pageX
    number pageY
    DOMEventTarget relatedTarget
    number screenX
    number screenY
    boolean shiftKey

    client는 현재 브라우저 화면, page는 전체 문서, screen은 모니터, offset은 이벤트 대상 기준 상대값 좌표를 각각 반환한다.

     

    8) Pointer 이벤트 : 마우스뿐만 아닌 펜, 터치스크린 등 하드웨어 상관없이 모든 포인터 이벤트에 대한 리스너

    * 포인터는 아직 모든 브라우저에서 지원되지 않는다. (현시점에선, Chrome, Firefox, Edge, IE)

    • onPointerUp
    • onPointerDown
    • onPointerCancel
    • onPointerOver
    • onPointerMove
    • onPointerOut
    • onPointerEnter
    • onPointerLeave
    • onGotPointerCapture
    • onLostPointerCapture

    * 속성

    마우스 이벤트의 속성들과 더불어, 아래 속성들을 반환한다.

    number pointerId
    number width
    number height
    number pressure
    number tangentialPressure
    number tiltX
    number tiltY
    number twist
    string pointerType
    boolean isPrimary

     

    9) Selection 이벤트 : 텍스트가 선택되었을 때 이벤트 리스너

    • onSelect

    10) Touch 이벤트 : 터치 스크린 등 하드웨어에 대응하는 이벤트 리스너

    • onTouchStart
    • onTouchMove
    • onTouchEnd
    • onTouchCancel

    * 속성

    boolean altKey
    DOMTouchList changedTouches
    boolean ctrlKey
    boolean getModifierState(key)
    boolean metaKey
    boolean shiftKey
    DOMTouchList targetTouches
    DOMTouchList touches

     

    11) UI 이벤트

    • onScroll : 스크롤 이벤트에 대한 리스너. 마우스 스크롤뿐만 아니라, 마우스 및 키보드 버튼 등 모든 스크롤 동작을 감지

    * 속성

    number detail
    DOMAbstractView view
    

     

    12) Wheel 이벤트

    • onWheel : 마우스 휠에 대한 이벤트 리스너

    * 속성

    number deltaMode
    number deltaX
    number deltaY
    number deltaZ

     

    13) Media 이벤트 : 동영상 등 미디어파일에 관한 이벤트 리스너

    • onAbort
    • onCanPlay
    • onCanPlayThrough
    • onDurationChange
    • onEmptied
    • onEncrypted
    • onEnded
    • onError
    • onLoadedData
    • onLoadedMetadata
    • onLoadStart
    • onPause
    • onPlay
    • onPlaying
    • onProgress
    • onRateChange
    • onSeeked
    • onSeeking
    • onStalled
    • onSuspend
    • onTimeUpdate
    • onVolumeChange
    • onWaiting

     

    14) Image 이벤트 : <img> 태그에 관한 이벤트 리스너(Generic)

    • onLoad
    • onError

     

    15) Animation 이벤트 : CSS 애니메이션에 관한 이벤트 리스너

    • onAnimationStart
    • onAnimationIteration
    • onAnimationEnd

    * 속성

    string animationName
    string pseudoElement
    float elapsedTime

     

    16) Transition 이벤트

    • onTransitionEnd : CSS Transition이 종료되었을 때 이벤트 리스너

    * 속성

    string propertyName
    string pseudoElement
    float elapsedTime

     

    17) 기타 이벤트

    • onToggle : HTML5에 추가된 속성으로, <details> 요소를 열거나 닫을 때 이벤트 리스너

    같은 e(event)라고 막연하게 생각했지만, Javascript의 이벤트 객체와는 사뭇 다른 React의 합성 이벤트였다!

     

    또한, Mouse Hover 이벤트의 차이점을 정리하고자 시작했지만, 정말 많은 종류의 이벤트 리스너를 지원하고 있음을 새로이 알게 되었다.

    특히, 마우스 못지않게 많이 사용한 Key 이벤트에서 up/down은 value, press는 ASCII 값을 사용한다는 차이점도 새로이 배웠다.

     

    [출처]

    - React 공식문서 번역본 : ko.reactjs.org/docs/events.html#mouse-events  

    - 전민정 님의 블로그 : minjung-jeon.github.io/React-SyntheticEvent/

     

    반응형
Designed by Tistory.