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 버전을 한 페이지에서 사용할 수 있도록 준비하는 것이 주 목적이었고, 이 이벤트 위임 변경도 그 일환이었다.

React 17에서 이벤트 위임 변경사항 대응하기