본문 바로가기
WEB/깊게 공부하기

React가 이벤트를 관리하는 방식 - 3 (완)

by IT황구 2023. 6. 19.
728x90
반응형

https://rbals0445.tistory.com/139

 

React가 이벤트를 관리하는 방식 - 2

https://rbals0445.tistory.com/138 React가 이벤트를 관리하는 방식 - 1 올해가 가기 전 리액트를 소스코드 레벨에서 분석해보는게 목표였습니다. 목표를 간단하게 잡고 분석을 해보자 했지만, 생각보다 모

rbals0445.tistory.com

 

지난 글에서 이벤트 발생시에 등록했던 이벤트 핸들러가 어떻게 작동하는지 알아봤습니다.

 

코드 분석을 하면서 얻게된 내용들을 최종적으로 정리할 예정입니다.

 

 

리액트에서 이벤트 버블링을 사용하면 안되는 이유?

 

 

약 반년전에 회사 소스코드에다가 이벤트 버블링으로 함수를 작성한적이 있었습니다.

당시에 작성하고나서 효율적으로 작성했군.. 하면서 PR을 올리고 리뷰를 기다렸었습니다.

 

물론 반려되었습니다.. 이벤트 핸들러를 직접 달아주는 방향으로 수정했습니다. 하지만 리액트에서 버블링으로 이벤트를 이미 처리하고 있다는 사실도 얼핏 알게 되었습니다.

 

주제를 이벤트 분석으로 정한 이유도 6개월 전의 그 내용이 생각난것도 한 몫 했습니다.

 

근거로 코드가 아닌 Dan abramov 의 코멘트도 사용을 할 예정입니다. Dan abramov가 만물의 창시자는 아니지만, 적어도 React core팀에서 근무하고 있으므로 충분히 신뢰도가 있다고 생각했습니다.

 

 

Q. 개발자가 이벤트 버블링으로 직접 처리해주면 그래도 더 낫지 않을까?

 

 

A. 위의 말이 참이 되려면, 리액트가 모든 이벤트를 각 엘리먼트마다 등록한다. 가 전제가 되어야 합니다. 일단 등록을 안합니다. (코드에서 확인한것 외에 Dan Abramov의 댓글도 있습니다. 17, 18버전은 root level이 맞습니다.)

 

그리고 가장 치명적인 단점이 있습니다. 데이터가 흐르는 방향이 하나 더 생기게 됩니다.

 

1. 리액트는 부모 -> 자식 방향으로 데이터가 흐릅니다. 하지만 버블링으로 이벤트를 처리할경우 (특히 합성이벤트 e에 custom property를 추가) 역방향으로 데이터의 흐름이 하나 더 생기게 됩니다. 아래의 사진을 보면 e.customText를 자식에서 설정하고, 부모에서 받아서 보는것을 확인할 수 있습니다.

 

 

역방향으로 데이터 흐름이 생기는게 무슨 문제가 있을까요?

 

디버깅을 한다고 가정해봅시다. 부모 -> 자식으로 명식적으로 값이 내려오는것을 알기에, 특정 값은 부모 컴포넌트에서 내려준것을 알 수 있습니다.

 

하지만 자식 -> 부모의 방향으로 올라올 수 있다면? 디버깅의 범위가 넓어지게 됩니다.

이벤트 버블링을 과하게 사용하는 예시를 들어보겠습니다.

 

A (부모) -> B -> C -> D (커스텀 property 생성)

 

A에서 event의 커스텀 속성을 활용 할 경우, 이 값이 B, C, D 어디서 온지 어떻게 알 수 있을까요?

 

리액트는 단방향 흐름을 철학으로 가져가고 있습니다. 직접 custom property를 통해서 버블링을 사용하는것은, 이를 거스르는 방법이라고 할 수 있습니다.

 

 

Dan Abramov 또한 좋은 방법이 아니라 말하고 있습니다. 

 

저는 다음과 같이 정리하고, 버블링을 사용하지 않기로 했습니다.

 

  버블링 사용 버블링 사용 X
코드의 양 적음 많음 (명시적으로 prop으로 내려야함)
디버깅 난이도 높음 낮음
리액트의 철학 one-way data flow를 깨는가? 아니오

 

저는 처음부터 이렇게 동의한것은 아니었습니다.

 

와... 그러면 5천개의 row면 5000개 다 생성한다고?? 이벤트 위임을 쓰면 메모리 절약할 수 있다던데? 라는 생각이 들었습니다.

 

엣지케이스를 만들어 보았습니다.

 

 

이벤트 1만 5천개를 생성하면 정말 성능이 나빠질까?

 

 

React에서는 '아니오' 라고 말할 수 있습니다.

 

성능의 기준이 속도 일수도 있지만, 속도는 사실상 크게 체감이 되지 않고, Memory 점유율을 기준으로 잡았습니다.

 

Memory를 너무 많이 잡아먹지 않을까? 1만 5천개를 한번에 렌더링 하는 사람도 없겠지만, 억지 케이스를 만들어 보았습니다.

 

이벤트 버블링 사용 O

 

 

FiberNode와 HTMLLIElement 개수를 통해 1만 5천개를 실제로 그렸다는것을 알 수 있습니다.

 

 

 

리액트에서 기본적으로 native event를 등록한것도 포함되어서 135개가 나오게 된 것입니다.

여기서 봐야할것은 9,720B => 9.7KB 입니다. 또한 이벤트 핸들러 하나당 72B 가 나오는것을 확인했습니다.

 

 

이벤트 버블링 사용 X

 

 

마찬가지로 FiberNode와 HTMLLIElement 개수를 통해 1만 5천개 통해서 실제로 그렸음을 알 수 있습니다.

 

또한 EventListener  15135개 인것을 알 수 있습니다.

 

이때 72 * 15135 = 1,089,720B =1.08MB 인것을 확인할 수 있습니다.

 

즉 억지로 짜내고 짜내서 1만 5천개를 달아도 약 1MB 정도의 차이인것입니다. 따라서 메모리를 많이 차지한다? 이것은 맞지 않습니다.

 

따라서 이벤트 버블링을 사용하나 안하나 차이가 없다고 봐도 무방할것 같다고 결론을 내렸습니다.

 

 

 

하지만...

 

 

여기서 아주 훌륭한 분들은 뭔가 이상한것을 눈치채셨을 것입니다.

엘리먼트에 직접 이벤트를 붙이지 않는다면서 왜 이벤트가 1만 5천개로 나오는것이지? 

 

이것은 IOS Safari 버그 때문에 empty handler가 추가되었기 때문입니다.

 

 

직접 예시 코드를 생성해서 Event Listener를 확인하면 실제로 등록되어있습니다.

 

 

하지만! 9665 Line을 찾아가보면 정말 아무 작업도 없는것을 알 수 있습니다

 

따라서 해당 이벤트를 지우더라도 정상적으로 작동이 됩니다. 그리고 위의 답변이 사실임을 알 수 있습니다.

 

 

 

정리

 

 

 

코드에서 확인한 내용들과 react 팀의 답변을 통해서 결론을 낼 수 있었습니다.

 

리액트로 우주선을 만드는게 아닌이상 이벤트 위임을 사용하지 않는것이 가독성 및 디버깅에도 훨씬 유리하다. 라고 결론 내릴 수 있습니다.

 

리액트는 버블링으로 이벤트를 잘 처리하고 있으니, 개발자들은 고민 없이 엘리먼트에 이벤트 핸들러를 등록해도 문제가 없습니다.

 

 

분석을 하면서 토끼굴에 여러번 빠졌었습니다. 내가 이걸 왜 보고있지? 라는 생각도 여러번 했는데, 적당히 TODO로 남겨두고, 끝까지 실행하는것을 보고나니 성취감은 있는것 같습니다.

 

특히나 소스코드가 클수록 이상한곳으로 흘러들어갈 확률이 높은것 같습니다. 내가 뭘 찾으려고 했는지 항상 생각하면서 분석해야 겠습니다.

 

감사합니다!

 

 

 

Reference

https://blog.cloudboost.io/why-react-discourage-event-delegation-2b5fe3f52bea

 

Why React discourage event delegation?

Experienced frontend developers should be familiar with event bubbling and event delegation. It is a nice pattern to use, why React…

blog.cloudboost.io

https://github.com/facebook/react/issues/10322#issuecomment-318907181

 

Custom field in event not cleaned up · Issue #10322 · facebook/react

Do you want to request a feature or report a bug? Bug What is the current behavior? The custom field in event does not clean up. The data appear in other event fired. If the current behavior is a b...

github.com

 

https://github.com/facebook/react/issues/13625

 

How event delegation works in React? · Issue #13625 · facebook/react

I've been reading statements like this one in multiple articles: Event delegation: React doesn't actually attach event handlers to the nodes themselves. When React starts up, it starts listening fo...

github.com

 

728x90
반응형