Home Handling Events
Post
X

Handling Events

Event

이벤트(event)란 여러분이 프로그래밍하고 있는 시스템에서 일어나는 사건을 말합니다.

예를 들면 “클릭을 했을 때”, “스크롤을 했을 때”, “무언가 입력했을 때” 등의 상호작용으로 인해 일어나는 사건을 말합니다.

즉, 해당 사건에 어떠한 방식으로 응답할 수 있도록 시스템이 말해주는 것입니다.


DOM의 Event Handling

HTML 요소(element)에서 발생하는 이벤트를 처리하는 가장 쉬운 방법은 HTML의 이벤트 속성을 활용하는 것입니다.

on + <이벤트 타입명> 형태를 갖는 이벤트 속성은 HTML의 모든 요소에 사용이 가능하며, 해당 타입의 이벤트 발생 시 실행할 자바스크립트 코드(Event Handler)를 속성값으로 설정해줄 수 있습니다.

1
2
3
// DOM 엘리먼트에서 이벤트 속성 작성 시 전부 소문자로 작성하며
// 속성 값을 문자열로 작성하여 이벤트 핸들러를 전달한다.
<button onclick="activateLasers()">Activate Lasers</button>

React의 Event Handling

React 엘리먼트에서 이벤트를 처리하는 방식은 DOM 엘리먼트에서 이벤트를 처리하는 방식과 매우 유사하지만, 몇 가지 문법 차이가 있습니다.

  • 소문자 대신 camelCase를 사용

    DOM 엘리먼트에서 onclick, onmouseover, onsubmit, onchange 등 전부 소문자로 작성됐던 이벤트 속성들은 React 엘리먼트에서는 각각 onClick, onMouseOver, OnSubmit, OnChange 등 camelCase로 작성되어야 합니다.

  • 이벤트 핸들러 이름

    • Props의 경우

      대부분 onClick과 같이 on 접두사 사용

    • Function Name의 경우

      대부분 handleClick과 같이 handle 접두사 사용

  • JSX를 사용하여 문자열이 아닌 함수로 Event Handler를 전달

    1
    
    <button onClick={activateLasers}>Activate Lasers</button>
    
  • Event 기본 동작 방지

    DOM 엘리먼트의 경우 이벤트 핸들러가 false를 반환해도 해당 엘리먼트의 기본 동작을 방지할 수 있습니다.

    하지만, React 엘리먼트의 경우 반드시 핸들러가 preventDefault를 호출해야합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    // DOM 엘리먼트에서는 핸들러가 false를 반환하면 a 태그의 기본 동작이 방지됨
    <a href="#" onclick="console.log('The link was clicked.'); return false">
      Click me
    </a>;
    
    function ActionLink() {
      function handleClick(e) {
        // React에서는 a 태그의 기본 동작을 막기위해서 preventDefault를 호출
        e.preventDefault();
    
        console.log("The link was clicked.");
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }
    

DOM 요소에만 이벤트 설정이 가능하며, 컴포넌트에는 불가능합니다.
컴포넌트의 경우는 단순히 props를 전달하게 됩닌다.


React 함성 이벤트 (Synthetic Event)

브라우저마다 Event 이름부터 종류나 처리 방식 등이 모두 다릅니다.

React는 Synthetic 이벤트로 브라우저마다 다른 nativeEvent를 묶어서 처리합니다. (크로스 브라우징 문제 해결)

즉, Event Handler는 모든 브라우저에게 SyntheticEvent 객체를 전달받습니다.

하지만 일부 DOM 이벤트는 SyntheticEvent에 존재하지 않을 수 있습니다.

참고 사이트 : React 합성 이벤트 공식 문서

  • 합성 이벤트 객체의 속성

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    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
    
  • React에서 지원하는 DOM Event

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Mouse 이벤트:
    onClick onContextMenu onDoubleClick onDrag onDragEnd
    onDragEnter onDragExit
    onDragLeave onDragOver onDragStart onDrop onMouseDown
    onMouseEnter onMouseLeave
    onMouseMove onMouseOut onMouseOver onMouseUp
    
    Form 이벤트:
    onChange onInput onInvalid onReset onSubmit
    

    참고 사이트 : React 공식문서


함수 컴포넌트의 Event Handling

함수 컴포넌트는 useState Hook을 사용하기 때문에 this가 필요하지않습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React, { useState } from "react";

const ConfirmButton = () => {
  const [isConfirmed, setIsConfirmed] = useState(false);

  const handleConfirm = () => {
    setIsConfirmed((prevIsConfirmed) => !prevIsConfirmed);
  };

  return (
    <button onClick={handleConfirm} disabled={isConfirmed}>
      {isConfirmed ? "확인됨" : "확인하기"}
    </button>
  );
};

export default ConfirmButton;

클래스 컴포넌트의 Event Handling

React에서는 DOM 엘리먼트가 생성된 후 리스너를 추가하기 위해 addEventListener를 따로 호출할 필요가 없습니다.
대신 엘리먼트가 처음 렌더링될때 리스너를 제공하면 됩니다.

아래의 예시를 보면, 이벤트핸들러를 클래스의 메서드로 만들었고 이를 컴포넌트 내에서 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React from "react";

import React, { Component } from "react";

class ConfirmButton extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isConfirmed: false,
    };

    // handle 메서드에 this를 바인딩합니다.
    this.handleConfirm = this.handleConfirm.bind(this);
  }

  // 함수 선언식으로 함수 선언
  handleConfirm() {
    this.setState((prevState) => ({
      isConfirmed: !prevState.isConfirmed,
    }));
  }

  render() {
    return (
      <button onClick={this.handleConfirm} disabled={this.state.isConfirmed}>
        {this.state.isConfirmed ? "확인됨" : "확인하기"}
      </button>
    );
  }
}

export default ConfirmButton;

JS의 class 메서드는 기본적으로 바인딩되어있지 않습니다.

this.handleConfirm 바인딩하지 않고 호출하면 this는 undefined가 됩니다.

매번 bind 메서드를 호출하는 것이 불편하다면, Class fields syntax를 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React from "react";

class ConfirmButton extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      isConfirmed: false,
    };

    // handle 메서드 bind 삭제
  }

  // 화살표 함수로 변경
  handleConfirm = () => {
    this.setState((prevState) => ({
      isConfirmed: !prevState.isConfirmed,
    }));
  };

  render() {
    return (
      <button onClick={this.handleConfirm} disabled={this.state.isConfirmed}>
        {this.state.isConfirmed ? "확인됨" : "확인하기"}
      </button>
    );
  }
}

export default ConfirmButton;
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.