현재 이벤트가 캡처링 / 버블링 단계에서 더 이상 전파되지 않도록 방지한다.
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
현재 이벤트가 캡처링 / 버블링 단계에서 더 이상 전파되지 않도록 방지하는 것은 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()
를 사용해 이벤트 전파를 막고 둘의 차이를 확인해보자.
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개는 모두 실행되었다.
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 제대로 이해하기
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 이벤트는 정상적으로 실행된다.