React 17에서 이벤트 위임 변경사항 대응하기
문제 상황
레거시 jQuery 플러그인과 React 컴포넌트가 혼재된 프로젝트를 React 17로 업그레이드했다. 업그레이드 후 특정 모달 컴포넌트에서 외부 클릭 감지가 제대로 동작하지 않는 이슈가 발생했다.
원인 분석
React 17부터 이벤트 위임 방식이 변경되었다. 기존에는 모든 이벤트를 document에 연결했지만, 17부터는 React 트리가 렌더링되는 root DOM 노드에 연결한다.
// React 16 이하
document.addEventListener('click', ...)
// React 17 이상
const root = document.getElementById('root');
root.addEventListener('click', ...)
우리 코드는 document 레벨에서 클릭 이벤트를 캐치하고 있었는데, React의 stopPropagation()이 더 이상 document까지 전파를 막지 못하게 되면서 의도치 않은 동작이 발생했다.
해결 방법
이벤트 리스너를 등록하는 순서와 레벨을 조정했다. document 레벨 리스너에서 React root를 체크하는 로직을 추가했다.
document.addEventListener('click', (e) => {
const reactRoot = document.getElementById('root');
if (reactRoot.contains(e.target)) {
// React 영역 내 클릭은 React에서 처리
return;
}
// 외부 영역 클릭 처리
});
장기적으로는 jQuery 의존성을 제거하고 모든 이벤트를 React 내부에서 처리하도록 리팩토링하는 것이 맞지만, 당장은 이 방식으로 호환성을 유지했다.
참고사항
React 17은 주요 기능 추가 없이 점진적 업그레이드를 위한 버전이다. 여러 React 버전을 한 페이지에서 사용할 수 있도록 준비하는 것이 주 목적이었고, 이 이벤트 위임 변경도 그 일환이었다.