이 시리즈는 "가장 쉬운 웹개발 with Boaz" 님의 [React 까보기 시리즈] 를 기반으로 만들어졌습니다.
Virtual DOM의 동작을 Render Phase와 Commit Phase로 나누어서 살펴볼 예정입니다.
VDOM은 프로그래밍 컨셉입니다. 메모리 상에 UI와 관련된 정보를 띄우고, react-dom(renderer)과 같은 라이브러리에 의해 실제 DOM과 sync를 맞춥니다 이 과정을 재조정(reconciliation)이라 부르고 reconciler가 관여합니다.
왜 가상으로 할까요? 실제 DOM으로 구현한다면 mount와 paint 작업이 들어가기 때문에 가상보다 비용이 더 크게 됩니다.
VDOM은 어떻게 구현되어 있을까요? 아래의 그림처럼 Fiber node
로 구성된 Tree 형태입니다.
Fiber node
입니다.Tree가 2개가 존재합니다. current
트리와 workInProgress
트리입니다.
current
current
트리의 끝을 보시면 render
라는 함수의 인자로 들어가게 되는 것을 보실 수 있습니다. const root = React.createRoot(document.getElementById('root') as HTMLElement)
위의 과정을 거쳐 실제 HTML의 Element를 current
트리의 Root로 만듭니다. 루트를 만든 뒤에는 root.render()
API를 통해 current
트리를 만듭니다.
workInProgress
current
트리에서 자기복제하여 만들어졌으며 alternate
로 서로를 참조합니다. fiber
는 첫 번째 자식만을 child
속성으로 참조하며 나머지 자식들을 sibling
으로 참조합니다. 모든 자식은 부모를 return
속성으로 참조합니다.fiber
는 자바스크립트 객체입니다)workInProgress
트리는 current
트리가 됩니다.Root Node
의 current
속성을 current
트리에서 workInProgress
트리로 변경하면 됩니다. 그리고,current
트리에서 또 자기복제를 통해 새로운 workInProgress
트리를 만듭니다.위 과정에 대한 설명을 들었으면 동일한 트리가 2개를 가지고 있다는 생각이 들 것입니다. 이러한 구조를 더블 버퍼링
이라 부릅니다.
왜 더블 버퍼링 구조를 갖게 되었을까요? 직접 작업 중인 workInProgress
트리를 특정한 이유로 다 삭제해야할 때나 유연하게 순서를 조정해야 할 때가 있는데, 그러기 위해서는 원본이 필요하고 원본을 참조해야할 수 있습니다.
컴포넌트 리렌더링은 컴포넌트 호출 후 그 결과가 VDOM에 반영됩니다. DOM에 mount되어 paint되는 것이 아닙니다.
render phase
와 commit phase
가 리액트 라이프 사이클 안에 있는 단계입니다.
VDOM을 재조정(reconciliation)하는 단계입니다.
fiber Node
로 확장된 객체를 추가, 수정, 삭제하는 것을 말하며, reconciliation(추가, 수정, 삭제 작업)이 일어나기 위해서는 WORK를 scheduler에 등록해야 합니다.react element
를 fiber Node
로 확장시켰다는 의미abort
, stop
, restart
등의 메서드를 호출하면서 멈출 수도, 다시 시작할수도 있게 되었습니다. (즉, useTransition
등의 API를 통해 렌더링 우선순위 변경이 가능합니다.)재조정이 끝난 VDOM을 DOM에 적용하고, 라이프사이클을 실행하는 단계입니다.
일관성을 위해 동기적으로 실행을 합니다.
결과적으로 DOM 조작이 다 처리(일괄처리)를 하고, 리액트가 콜스택을 비워준 다음에서야 브라우저가 조작이 끝난 DOM에 대해 Paint를 시작하게 됩니다