리액트의 이벤트 위임

이벤트 위임이란?

자식 요소의 이벤트를 각 요소별로 처리하지 않고 부모 요소 하나에서 통합적으로 처리하는 방식이다.

자바스크립트에서의 이벤트 위임

<ul id="list">
  <li>아이템 1</li>
  <li>아이템 2</li>
  <li>아이템 3</li>
  <li>아이템 4</li>
</ul>

<li>에 클릭이벤트를 넣고자 할 때, 다음과 같이 이벤트 위임을 사용해 구현할 수 있다.

const list = document.getElementById("list");

list.addEventListener("click", function (event) {
  console.log("클릭된 아이템:", event.target.textContent);
});

자바스크립트에서 이벤트 위임을 했어야만 했던 이유

  • 수백 개의 버튼이나 리스트 항목에 각각 이벤트 리스너를 달면 메모리와 성능에 큰 부담이 된다.
  • 동적 DOM 조작 시, 나중에 추가된 요소에 이벤트를 다시 바인딩해야 함.
  • 부모 요소 하나에만 바인딩하면, 이후 추가된 요소도 자동으로 처리 가능.

위에 있던 코드를 리액트로 구현한다면 이런 느낌이다.

import React from "react";

function EventDelegationList() {
  const handleClick = (event) => {
    console.log("클릭된 아이템:", event.target.textContent);
  };

  return (
    <ul onClick={handleClick}>
      <li>아이템 1</li>
      <li>아이템 2</li>
      <li>아이템 3</li>
      <li>아이템 4</li>
    </ul>
  );
}

export default EventDelegationList;

하지만 아무도 이런식으로 작성하지 않는다. 이유는 두가지 때문이다.

1) 리액트는 내부적으로 이벤트 위임을 사용하고 있다.

리액트는 기본적으로 모든 이벤트를 루트에 바인딩하므로, 별도로 구현할 필요가 없다.

이미 성능 최적화가 되어 있어 이벤트를 각각 처리할 때와 성능 차이가 거의 없다.

2) 동적으로 생성된 요소에 이벤트를 다시 바인딩 할 필요가 없다.

리액트는 virtual DOM 업데이트 과정에서, DOM 요소 자체를 교체하지 않고 내부 텍스트 노드나 속성만 수정한다.

DOM 노드 자체가 유지되므로, 기존 이벤트 바인딩도 그대로 유지된다.

자바스크립트와 리액트의 이벤트 위임

자바스크립트의 이벤트 처리 과정

사용자 이벤트 발생

사용자가 버튼을 클릭하거나 키를 입력하면 브라우저가 가장 먼저 이벤트를 감지한다.

네이티브 이벤트 객체 생성

브라우저는 네이티브 이벤트 객체를 생성하여 이벤트와 관련된 정보를 담는다.

이벤트 전파

3-1) 캡처링 단계

최상위 요소부터 타깃 요소까지 내려가며 이벤트를 전달한다.

3-2) 버블링 단계

타깃에 도착하면 타깃에서 다시 최상위 요소로 올라가며 이벤트를 전달한다.

이벤트 핸들러 실행

각 단계에서 이벤트 핸들러를 만나면 바로 실행된다.

캡쳐링에서는 기본적으로 핸들러 감지가 안되며, 버블링에서는 핸들러가 모두 실행된다.

이벤트 전파 종료

버블링 단계에서 최상위 요소에 도달하면 이벤트 처리가 종료된다.

이벤트 객체는 메모리에서 사라진다.

리액트의 이벤트 처리 과정

사용자 이벤트 발생

사용자가 버튼을 클릭하거나 키를 입력하면 브라우저가 먼저 이벤트를 감지한다.

네이티브 이벤트 객체 생성

브라우저는 네이티브 이벤트 객체를 생성한다.

캡쳐링 & 버블링 과정

합성이벤트 처리

합성이벤트 객체는 버블링 경로를 따라가면서 각 요소의 핸들러를 만나면 바로 실행한다.

실제 실행은 루트에서 제어하지만, 각 요소에서 실행된 것처럼 보이게 처리한다.

참고) SyntheticEvent란?

리액트는 네이티브 DOM 이벤트 객체를 감싸서 사용하는 합성이벤트 객체를 만든다. 이 객체를 통해 이벤트를 처리한다.

네이티브 DOM 이벤트 객체: 브라우저가 생성한 이벤트 객체

SyntheticEvent의 구조

리액트의 SyntheticEvent는 다음과 같은 속성을 가지며, 네이티브 이벤트와 유사한 인터페이스를 제공한다.

속성

nativeEvent: 실제 DOM 이벤트 객체

currentTarget: 이벤트가 처리되는 요소

target: 이벤트가 발생한 요소

type: 이벤트 유형 (예: click, change)

bubbles, cancelable: 이벤트의 버블링 여부, 취소 가능 여부

preventDefault(): 기본 동작을 방지

stopPropagation(): 이벤트 전파를 중단

isDefaultPrevented(): preventDefault()가 호출되었는지 확인하는 메서드

isPropagationStopped(): stopPropagation()이 호출되었는지 확인하는 메서드