생각해보니... react에서는 일반적으로 props drilling을 통해서 eventHandler를 전달하는데, 그렇게 되는 것이 더 편한건 알겠지만, 왜 그렇게 하는 것인지에 대해서는 알지 못했다.
기존 이벤트 버블링, 캡쳐링 프로세스는
$('.add-button').click(function() {
$('.container').append('<button class="button">Click Me</button>');
})
$('.container').on('click', '.button', function() {
alert('Hello!');
})
react 에전 jquery의 시대에는 이러한 패턴을 자주 썼다고 한다.
상위에 리스너를 하나 걸어놓으면, 아래에서 일어나는 이벤트를 모두 확인 가능했기 때문에
react에서는?
class Card extends React.Component {
onClickHandler = () => {
alert('Hello World!');
}
render() {
return (
<div
className='card'
onClick={ this.onClickHandler }
>
<img
className='icon'
src='https://facebook.github.io/react/img/logo.svg'
/>
<h2 className='title'>Why React discourage event delegation?</h2>
<p className='excerpt'>Experienced frontend developers should be familiar with event bubbling and event delegation...</p>
</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<Card/>
</div>
);
}
}
ReactDOM.render(<App name="world"/>, document.getElementById('container'));
리액트 역시 버블링은 동일하게 동작한다.
위 코드를 본다면, Card class의 상위 div에 onCLick을 하나 걸어놓는 것으로 nested된 모든 엘리먼트에 클릭 이벤트가 위에서 참조할 수 있게 된다.
하지만 1. 예시와 다른 점은 리액트에서는 이와는 다르게 SyntheticEvent라는 방식으로 이벤트를 다룬다.
SyntheticEvent는 브라우져의 이벤트 오브젝트의 Wrapper이며, stopPropagation(버블링 막음)이나 preventDefault(새로고침 막음)같은 메소드도 사용 가능하다.
가장 큰 차이점은 react에서는 2. 예시처럼 이벤트 핸들링 시 모든 노드에 핸들러를 붙이지 않는다는 것이다.
리액트에서는 위와 같은 방식(맨 상위부터 아래로 내려가는 방식) 대신,
1. 이벤트를 클릭할 시 타켓 엘리먼트를 먼저 부른다(타게팅 단계),
2. 그리고 버블링한다.
하지만 onClickCapture를 이용해서 capturing을 활성화 시킬 수도 있다.
import React, { Component } from "react";
class Molly extends Component {
...
// 일반적으로 캡쳐링을 이용하려면 elem.addEventListener(..., {capture: true}) 식이지만
// react에서는 onClickCapture를 사용하지 않으면 capturing 단계가 일어나지 않음.
render() {
return (
<div className="im-a-parent" onClickCapture={this.handleCallFamilyToEat}>
<button className="im-a-child" onClick={this.handleCookEggs}>Cook Eggs</button>
<button className="im-a-child" onClick={this.handleMakeRice}>Make Rice</button>
<button className="im-a-child" onClick={this.handleMixChicken}>Mix Chicken</button>
</div>
);
}
}
export default Molly;
p.s.)
react fiber 도입된 버전은 16.
리액트 16버전까지는 SyntheticEvents가 실제 dom tree 처럼 버블링시 맨 상위 버전까지 버블링이 일어났다. eventListener를 모든 요소에 붙이게 된다는 것.
하지만 리액트 17버전 부터는 이벤트 자체가 react의 root element (index.html에 있는) 까지만 전달된다고 한다.
참고한 url
https://blog.cloudboost.io/why-react-discourage-event-delegation-2b5fe3f52bea