stopPropagation(), stopImmediatePropagation(), preventDefault() 비교

선정·2023년 2월 27일
1

1. Event.stopPropagation()

현재 이벤트가 캡처링 / 버블링 단계에서 더 이상 전파되지 않도록 방지한다.

function App() {
  const handleClickBtn = () => {
    console.log('button')
  }

  return (
    <div onClick={() => console.log("div")}>
      <span onClick={() => console.log("span")}>
        <button onClick={handleClickBtn}>
          button
        </button>
      </span>
    </div>
  )
}

export default App

위의 코드에서 <button>을 클릭하면 이벤트 전파에 따라 클릭하지 않은 상위 요소에도 클릭 이벤트에 따른 이벤트 핸들러가 실행되어 콘솔에 차례로 "button", "span", "div" 가 출력된다.

이와 같은 이벤트 전파를 막고 싶을 때, stopPropagation() 메서드를 사용한다. 아래와 같이 해당 메서드를 사용해 이벤트 전파를 막고 <button> 을 클릭하면 이제 콘솔창에는 "button" 만 출력된다.

function App() {
  const handleClickBtn = (e) => {
    e.stopPropagation()
    console.log('button')
  }

  return (
    <div onClick={() => console.log("div")}>
      <span onClick={() => console.log("span")}>
        <button onClick={handleClickBtn}>
          button
        </button>
      </span>
    </div>
  )
}

export default App


2. Event.stopImmediatePropagation()

현재 이벤트가 캡처링 / 버블링 단계에서 더 이상 전파되지 않도록 방지하는 것은 stopPropagation() 와 동일하나, stopImmediatePropagation() 은 동일한 요소에 발생한 동일한 이벤트에 대한 또다른 이벤트 핸들러의 실행도 막는다.

동일한 html 요소에서 발생한 동일한 이벤트에 대해 하나 이상의 이벤트 핸들러를 할당할 수 없는 이벤트 핸들러 어트리뷰트 방식 으로 이벤트를 처리하는 리액트에서는 stopPropagation() 와의 차이를 비교할 수 없을 것 같다.

HTML과 자바스크립트 코드로 예시를 들어 확인해 보자.

<div id="div">
  <span id="span">
    <button id="button">button</button>
  </span>
</div>
const div = document.getElementById('div')
const span = document.getElementById('span')
const button = document.getElementById('button')

div.addEventListener("click", () => console.log("div click"))
span.addEventListener("click", () => console.log("span click"))
button.addEventListener("click", () => console.log("button click 1"))
button.addEventListener("click", () => console.log("button click 2"))

이벤트 전파를 막지 않고 버튼을 클릭 했을 때, 버블링에 따른 이벤트 전파가 발생한다. 이제 stopPropagation()stopImmediatePropagation() 를 사용해 이벤트 전파를 막고 둘의 차이를 확인해보자.

stopPropagation() 실행 결과

const div = document.getElementById('div')
const span = document.getElementById('span')
const button = document.getElementById('button')

div.addEventListener("click", () => console.log("div click"))
span.addEventListener("click", () => console.log("span click"))
button.addEventListener('click', (e) => {
  e.stopPropagation() // stopPropagation()으로 이벤트 전파 방지
  console.log('button click 1')
})
button.addEventListener("click", () => console.log("button click 2"))

위의 코드에서 <button> 을 클릭해 실행된 결과를 보면 상위 요소로의 이벤트 전파는 막히고, <button> 에 등록된 이벤트 핸들러 2개는 모두 실행되었다.

stopImmediatePropagation() 실행 결과

const div = document.getElementById('div')
const span = document.getElementById('span')
const button = document.getElementById('button')

div.addEventListener("click", () => console.log("div click"))
span.addEventListener("click", () => console.log("span click"))
button.addEventListener('click', (e) => {
  e.stopImmediatePropagation() // stopImmediatePropagation()으로 이벤트 전파 방지
  console.log('button click 1')
})
button.addEventListener("click", () => console.log("button click 2"))

stopPropagation()를 사용했을 때와 달리 "button click 2" 는 콘솔에 출력되지 않았다. stopImmediatePropagation() 는 상위로의 이벤트 전파 뿐만 아니라 같은 요소에 발생한 동일한 이벤트에 대한 다른 이벤트 핸들러의 실행까지 막는 것을 확인 할 수 있다.

두 메서드의 차이에 대해 제대로 이해하고 싶다면 참고할만한 포스팅
stopPropagation vs stopImmediatePropagation 제대로 이해하기


3. Event.preventDefault()

DOM 요소의 기본적인 동작을 실행하지 않도록 중단시킨다. 보통 <a>, <form> 요소에서 많이 사용하는 듯하니 이 두가지 예시로 확인해보자.

<a> 요소의 href 어트리뷰트 값으로의 이동 막기

function App() {
  const preventDefault = (e) => {
    e.preventDefault()
  }

  return <a href="https://stackblitz.com/" onClick={preventDefault}>stackblitz</a>
}

export default App

preventDefault()로 인해 <a> 요소를 클릭해도 href 어트리뷰트에 지정된 링크로 이동하지 않는다.

<form> 요소의 새로고침 막기

import { useState, useRef } from 'react'

function App() {
  const [value, setValue] = useState("")
  const [items, setItems] = useState([])
  const id = useRef(1)

  const onSubmit = (e) => {
    e.preventDefault()
    const newItem = { id: id.current, text: value }
    setItems((prev) => [...prev, newItem])
    id.current += 1
    setValue('')
  }

  return (
    <>
      <form onSubmit={onSubmit}>
        <input
          type="text"
          value={value}
          onChange={(e) => setValue(e.target.value)}
        />
        <button>제출</button>
      </form>
      <hr />
      <ul>
        {items.map((item) => (
          <li key={item.id}>{item.text}</li>
        ))}
      </ul>
    </>
  )
}

export default App

form 요소에서는 submit 이벤트가 발생할 때마다, 기본 동작으로 페이지가 깜빡거리며 새로고침 된다. 이 때 preventDefault() 를 사용하면 새로고침은 중단되고 그 외 submit 이벤트는 정상적으로 실행된다.

profile
starter

0개의 댓글