김호준
About

리액트의 가상 DOM 방식은 브라우저의 일반적인 DOM을 관리하는 방식보다 빠르다는 것은 사실이 아니다

virtual dom은 개발자의 개발 생산성을 높이고 일관되게 작업할 수 있다는 이점이 있고, 상태가 변경될때마다 렌더링을 할 수 있다는 이점이 있다. 가상 DOM은 일반적으로 충분히 빠르지만 브라우저의 dom보다 빠르지 않고 최적화에 대해 고민해야 한다.

virtual DOM이라는 용어에 대해서

리액트를 개발한 개발자도 virtual DOM이라는 용어 자체를 폐기할 것을 권고하고 있다고 합니다. virtual DOM은 리액트의 reconciliation과정(리액트의 UI트리를 관리하는 과정)을 명확히 하기 위해 도입했지만 DOM의 이슈를 극복하기 위해 virtual DOM을 도입했다는 오해를 하고 있고 리액트의 의도와 다르게 해석되고 있기 때문이다. 오히려 UI를 값으로 다룬다는 의미에서 "value UI"라 표현하기를 권고한다고 합니다.

책을 읽다가 fiber에 대해서 나와서 구글링을 해봤는데 네이버 개발 블로그에 (opens in a new tab)에 좋은 글이 있어서 읽고 정리하여 요약해보려 했으나 책을 더 읽어보니 바로 뒷장에 훨씬 더 쉽게 요약되어 있어 블로그 주소를 첨부합니다. fiber에 대해 더 알고 싶다면 저 링크 게시글을 읽어보는 것을 추천드립니다. 정말 좋은 글인 것 같습니다.

리액트의 전역상태관리와 useContext

예전에 useContext가 있는데 전역 상태 관리 라이브러리 (redux, recoil, ...)가 필요한지에 대해서 생각했던 적이 있습니다. 그래서 그때는 useContext를 사용한다면 각기 다른 상태마다 context 객체를 생성해주어야 하고 값이 빈번하게 바뀌는 상태와 구독하고 있는 컴포넌트의 렌더링 최적화를 고려해주어야 한다. 또한 상태관리 라이브러리는 액션 함수와 스토어를 분리해서 상태관리가 가능하고 내부적으로 렌더링 최적화를 알아서 고려해준다는 장점이 있어서 전역 상태관리를 한다면 상태 관리 라이브러리를 사용하는게 효율적이고 useContext는 아코디언이나, 토스트와 같은 재사용 가능하고 복잡한 컴포넌트 패턴에서 프롭스 드릴링을 피하고 상태관리를 효율적으로 할 때 사용하기 좋다는 결론을 얻었습니다. 책에서는 reconciliation, fiber와 같은 개념을 언급해주고 상태관리 라이브러리 설치 필요성에 대해서 설명해주니 또 다른 관점으로 보게 되는 것 같아서 좋았습니다.

메모이제이션에 대해 다른 분들의 생각??

  • 주장 1 : 섣부른 최적화는 독이다, 꼭 필요한 곳에만 메모이제션을 추가하자
  • 주장 2 : 렌더링 과정의 비용은 비싸다, 모조리 메모이제이션해 버리자
    • 잘 살펴보고 일부에만
    • 일단 그냥 다

저자의 의견

메모이제이션은 하지 않는 것보다 메모이제션했을 때 더 많은 이점을 누릴 수 있다. 이것이 비록 섣부른 초기화라도 누릴 수 있는 이점이 더 크고, 실수로 빠트렸을 때 치러야 할 위험 비용이 더 크기 때문에 가능한 한 모든 곳에 메모이제션을 활용하자

내 의견

  • 섣부른 최적화는 오히려 독이다.

memo는 우선 첫 번째 렌더링을 더 빠르게 만들지 않는다. 업데이트 시 불필요한 작업을 건너뛰는 데에만 도움이 된다. 대부분의 앱은 인터렉션이 투박하거나 심플하다. (페이지 이동, 교체)는 일반적으로 메모화가 필요하지 않음, 반면 그래픽 작업이나 도형 이동과 같은 인터랙션은 메모화가 유용하다 계산이 눈에 띄게 느리고 의존성이 거의 변하지 않는 경우는 메모이제이션이 유용하다 하지만 그 이외에 경우에는 전달한 값은 나중에 어떤 훅의 의존성으로 쓰일 수도 있다. 코드의 가독성이 떨어질 수 있다. "항상 새로운" 단일 값만으로도 전체 컴포넌트에 대한 메모화가 깨질 수 있다.

불필요한 메모화를 없애기 위한 원칙

  • 컴포넌트의 자식으로 만들기 children (opens in a new tab)
  • 필요 이상으로 state를 끌어올리지 않는다.
  • 렌더링 로직을 순수하게 유지하자
  • 불필요한 effect를 피하자

결론은 메모이제이션이 필요한 경우는 아주 무거운 계산이 필요한 작업이나 변하지 않는 값을 너무 반복적으로 불필요하게 계산해야 할 때 쓸 수 있다. 하지만 이러한 경우는 누구라도 당연히 성능 최적화에 대한 고민을 할 것이고 이밖에 다른 경우에는 섣부른 최적화는 오히려 메모리 낭비이고 독이라고 생각한다. 또한 반복적이고 불필요한 계산이더라도 시간이 많이 걸리지 않는다면 사용자는 메모이제이션을 한 경우와 그렇지 않은 경우의 차이를 느끼기 어렵고 오히려 메모이제이션으로 낭비되는 메모리 비용이 더 크다. 섣부른 최적화보다는 불필요한 이펙트를 발생시키고 있는 것은 아닌지, 코드를 잘못 짠것은 아닌지 고민하는게 더 좋지 않을까