[React] 기초 | 리액트에서의 버블링과 캡쳐링 방지법

Re_Go·2024년 10월 5일
0

React

목록 보기
12/12
post-thumbnail
post-custom-banner

1. 버블링과 캡처링의 정의

우선 버블링부터 설명해 보자면, 버블링DOM 트리에서 이벤트가 발생했을 때, 그 이벤트가 발생한 특정 요소에서부터 상위 부모 요소로 전파되는 방식입니다. 즉, 가장 구체적인 요소(이벤트가 발생한 요소)에서부터 시작하여 점점 더 넓은 범위(부모, 조상 요소 등)로 이벤트가 전파되는 현상인데요

예를 들어, 클릭 이벤트가 특정 버튼 요소에서 발생하면, 그 이벤트는 버튼의 부모 요소, 그 부모의 부모 요소로 차례대로 전파되는데, 이때 부모 요소 중 이벤트 리스너를 등록 하고 있는 부모 요소는 해당 이벤트 리스너가 실행되는 현상인거죠.

자료 출처 : https://velog.io/@falling_star3/JS-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81bubbling%EA%B3%BC-%EC%BA%A1%EC%B2%98%EB%A7%81capturing-event.TargetcurrentTarget

반대로 캡처링버블링과 반대로 부모 요소의 이벤트 발생이 하위 요소까지 전달되는 현상을 의미하는데요. 이러한 이벤트 전파 방식은 리액트뿐만 아니라, DOM의 기본적인 이벤트 전파 메커니즘으로, 모든 브라우저에서 동작하는 자연스러운 현상입니다.

이러한 이벤트 전파는 크게

① 부모에서 타겟으로 내려가면서 등록된 이벤트가 발생되는 캡처 페이즈,
② 타겟 자체에서 등록된 이벤트가 발생되는 타겟 페이즈,
③ 다시 타겟에서 부모로 올라가면서 등록된 이벤트가 발생되는 버블링 페이즈

로 구성됩니다.

자료 출처 : https://velog.io/@falling_star3/JS-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81bubbling%EA%B3%BC-%EC%BA%A1%EC%B2%98%EB%A7%81capturing-event.TargetcurrentTarget

그럼 카운터 앱 코드를 예시로 버블링과 캡쳐링이 어떻게 일어나는지를 아래의 코드를 잠깐 살펴볼까요?

import { useState } from "react";

function CounterApp() {
  const [count, setCount] = useState(0);

  // 캡처링 단계에서 실행될 함수
  const handleParentClickCapture = () => {
    console.log("부모 캡처링 단계 발생 (count: " + count + ")");
  };

  // 버블링 단계에서 실행될 함수
  const handleParentClick = () => {
    console.log("부모 버블링 단계 발생 (count: " + count + ")");
  };

  // 증가 버튼 클릭 핸들러
  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
    console.log("증가 버튼 클릭: " + count);
  };

  // 감소 버튼 클릭 핸들러
  const handleDecrement = () => {
    setCount((prevCount) => prevCount - 1);
    console.log("감소 버튼 클릭: " + count);
  };

  return (
    <div
      onClickCapture={handleParentClickCapture}  // 캡처링 단계에서 발생
      onClick={handleParentClick}                // 버블링 단계에서 발생
      style={{
        padding: "50px",
        border: "2px solid black",
        textAlign: "center",
      }}

      <h1>Counter: {count}</h1>
      <div>
        <button
          onClick={handleIncrement}
          style={{ margin: "10px", padding: "10px" }}

          Increment
        </button>
        <button
          onClick={handleDecrement}
          style={{ margin: "10px", padding: "10px" }}

          Decrement
        </button>
      </div>
    </div>
  );
}

export default CounterApp;

- 버블링과 캡처링 발생 과정 (캡처링 -> 버블링)

  • increment 버튼을 누르면 최상위 부모 요소인 <div> 태그에 등록된 onClickCapture 속성(태그의 고유 제공 속성)에 등록된 함수인 handleParentClickCapture 가 발동
  • 바로 하위 요소(눌려진 요소)에서 등록된 이벤트인 handleIncrement 실행
  • 하위 요소에서 이벤트가 발생되었으므로 다시 상위로부터 버블링이 전달되어 부모 요소인 <div> 태그에 등록된 onClick 속성(버블링 현상이 일어날 때 발동되는 속성이기도 함)에 등록된 함수인 handleParentClick 가 발동

2. 버블링과 캡처링을 방지하기 위한 방법

이렇듯 버블링과 캡처링으로 인해 발생되는 전파 현상, 그러니까 개발자의 컨트롤에서 벗어나는 이벤트의 발생 현상을 막기 위해서는 타겟이 되는 요소에 stopPropagation 함수를 걸어주면 되는데요. 아래의 코드 예시를 살펴볼까요?

import { useState } from "react";

function CounterApp() {
  const [count, setCount] = useState(0);

  // 캡처링 단계에서 실행될 함수
  const handleParentClickCapture = () => {
    console.log("부모 캡처링 단계 발생 (count: " + count + ")");
  };

  // 버블링 단계에서 실행될 함수
  const handleParentClick = () => {
    console.log("부모 버블링 단계 발생 (count: " + count + ")");
  };

  // 증가 버튼 클릭 핸들러 (이벤트 전파 중단)
  const handleIncrement = (event) => {
    event.stopPropagation(); // 이벤트 전파 중단 (버블링 차단)
    setCount((prevCount) => prevCount + 1);
    console.log("증가 버튼 클릭: " + count);
  };

  // 감소 버튼 클릭 핸들러 (이벤트 전파 중단)
  const handleDecrement = (event) => {
    event.stopPropagation(); // 이벤트 전파 중단 (버블링 차단)
    setCount((prevCount) => prevCount - 1);
    console.log("감소 버튼 클릭: " + count);
  };

  return (
    <div
      onClickCapture={handleParentClickCapture} // 캡처링 단계에서 발생
      onClick={handleParentClick} // 버블링 단계에서 발생
      style={{
        padding: "50px",
        border: "2px solid black",
        textAlign: "center",
      }}

      <h1>Counter: {count}</h1>
      <div>
        <button
          onClick={handleIncrement}
          style={{ margin: "10px", padding: "10px" }}

          Increment
        </button>
        <button
          onClick={handleDecrement}
          style={{ margin: "10px", padding: "10px" }}

          Decrement
        </button>
      </div>
    </div>
  );
}

export default CounterApp;

위 코드에서는 이벤트가 최초로 발생 되는 타겟 (DOM)의 이벤트에 stopPropagation 함수가 먼저 호출이 되는 것을 확인할 수 있습니다. 이렇게 되면 최초 이벤트 발생 타겟을 중심으로 버블링이 차단되기 때문에 부모로부터 자식에게 전파되는 캡처링과 타겟에서만 발생된 이벤트만 발생할 수 있습니다.

그러나 방금 말씀드린대로 위 코드에서 캡처링 속성은 설정이 되어있기 때문에(onClickCapture) 캡처링 전파는 발생이 되는데요. 현업에서는 굳이 onClickCapture 속성을 정의하지 않기 때문에 자주 사용되는 onClick 버튼에 등록된 이벤트 전파 발생 (버블링)에 대한 방지 방법만 알고 계셔도 충분합니다.

profile
인생은 본인의 삶을 곱씹어보는 R과 타인의 삶을 배워 나아가는 L의 연속이다.
post-custom-banner

0개의 댓글