event.target과 event.currentTarget의 차이
2025-02-12최근 면접에서 event.target
과 event.currentTarget
의 차이를 답변하는 질문이 있었습니다. 부끄럽게도 둘의 차이점을 반대로 얘기하는 대참사가 벌어졌죠. 그래서 저와 같은 분들이 없도록 포스트를 작성해보려고 합니다😂
이벤트 위임
둘의 차이점을 알기 전에 우선 JS의 이벤트 위임을 알아야 합니다. 이벤트 위임은 이벤트 리스너를 부모 요소에 등록하여, 하위 요소에서 발생하는 이벤트를 부모가 감지하고 처리하는 방법입니다.
이는 JS의 버블링 때문에 발생하는데, 버블링이란 자식 요소에서 발생하는 이벤트가 부모 요소로 전파되는 현상입니다. (그 반대는 캡처링입니다)
이벤트 위임은 주로 동적으로 생성되는 요소를 관리하기 위해 사용하죠.
<ul id="parent">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<button id="addItem">Add Item</button>
<script>
const parent = document.getElementById("parent");
const addItem = document.getElementById("addItem");
// ✅ 이벤트 위임: 부모 요소에서 클릭 이벤트 감지
parent.addEventListener("click", (event) => {
if (event.target.tagName === "LI") {
console.log(`Clicked: ${event.target.textContent}`);
}
});
// ✅ 동적으로 리스트 추가
addItem.addEventListener("click", () => {
const newItem = document.createElement("li");
newItem.textContent = `Item ${parent.children.length + 1}`;
parent.appendChild(newItem);
});
</script>
target과 currentTarget의 차이점
target
은 이벤트가 실제로 발생한 요소이며, currentTarget
은 이벤트가 등록된 요소입니다.
위의 코드에서 이벤트가 실행되면 target
은 li
이며, currentTarget
은 이벤트가 등록된 ul
이 되는 거죠.
React에선 왜 currentTarget을 사용할까?
React와 TS를 사용한다면 주로 currentTarget
을 사용합니다. 그러면 왜 currentTarget
을 사용할까요?
가장 큰 이유는 타입의 안정성과 React의 SyntheticEvent(합성 이벤트) 구조 때문입니다.
우선 TS에서는 event.target
과 event.currentTarget
의 타입이 다릅니다.
<button onClick={handleClick}>
<span>Click Me</span>
</button>
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log(event.currentTarget); // ✅ HTMLButtonElement (안전함)
};
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log(event.target); // ❌ TypeScript 오류 발생 가능
};
위 코드에서 currentTarget
은 이벤트가 발생한 위치와 상관없이 currentTarget
의 타입은 항상 HTMLButtonElement
이므로 TypeScript에서 안전합니다.
만약 span
을 클릭하는 경우, target
은 span
이 되므로 타입 오류가 발생할 가능성이 있습니다.
두 번째 이유로는 React의 이벤트 동작 방식에 있습니다. React에서는 이벤트 핸들러가 실행된 후 SyntheticEvent 객체를 초기화하여 메모리를 절약합니다.
평소에는 이런 동작이 문제가 되지 않지만, 만약 비동기 작업이 추가되면 문제가 발생할 가능성이 생깁니다.
const handleClick = () => {
setTimeout(() => {
console.log(event.target);
// 🚨 SyntheticEvent가 풀링되었으므로, event.target이 null이 될 가능성이 있음
}, 1000);
};
위 코드에서 handleClick
함수가 종료되면서, React는 SyntheticEvent를 풀링하여 메모리를 정리합니다. 메모리 정리가 끝난 뒤 setTimeout
이 실행되면서 event.target
을 참조하려 하지만, 이미 null
이 되어 있어 예상치 못한 사이드 이펙트가 발생할 가능성이 있습니다.
이를 막기 위해서는 target
을 미리 저장하거나 currentTarget
을 사용하여 이벤트 핸들러가 바인딩된 요소를 가리키는 방법으로 해결할 수 있습니다.
const handleClick = (event: React.MouseEvent) => {
const target = event.target;
setTimeout(() => {
console.log(target);
}, 1000);
};
이제는 여러분도 면접에서도 헷갈리지 않고, 확실하게 답변할 수 있을 것 같습니다!