모던 리액트 Deep Dive 책을 정리한 내용입니다.
가성 DOM을 만드는 과정을 리액트는 어떻게 처리하고 있을까? 리액트는 여러 번의 렌더링 과정을 압축해 어떻게 최소한의 렌더링 단위를 만들어 내는 것일까? 이러한 가상 DOM과 렌더링 과정 최적화를 가능하게 해주는 것이 바로 리액트 파이버다.
리액트 파이버는 리액트에서 관리하는 평범한 자바스크립트 객체다. 파이버는 파이버 재조정자(fiber reconciler)가 관리하는데, 이는 앞서 이야기한 가상 DOM과 실제 DOM을 비교해 변경 사항을 수집하며, 만약 이 둘 사이에 차이가 있으면 변경에 관련된 정보를 가지고 있는 파이버를 기준으로 화면에 렌더링을 요청하는 역할을 한다.
그리고 한 가지 중요한 것은 모든 과정이 비동기로 일어난다는 것이다.
사용자가 입력할 때마다 스택에 쌓이는 작업이 많아질수록 리액트는 동기식으로 이를 처리하려고 노력하면서 작업에 많은 시간이 소요될 것이고, 최악의 경우 글자 입력에 지연이 생길 수 있다.
이러한 기존 렌더링 스택의 비효율성을 타파하기 위해 리액트 팀은 이 스택 조정자 대신 파이버라는 개념을 탄생시킨다.
파이버는 리액트 요소와 유사하다고 느낄 수 있지만 한 가지 중요한 차이점은 리액트 요소는 렌더링이 발생할 때마다 새롭게 생성되지만 파이버는 가급적이면 재사용된다는 사실이다. 파이버는 컴포넌트가 최초로 마운트되는 시점에 생성되어 이후에는 가급적이면 재사용된다.
생성된 파이버는 state가 변경되거나 생명주기 메서드가 실행되거나 DOM의 변경이 필요한 시점 등에 실행된다. 그리고 중요한 것은 리액트가 파이버를 처리할 때마다 이러한 작업을 직접 바로 처리하기도 하고 스케줄링하기도 한다는 것이다.
리액트의 핵심 원칙은 UI를 문자열, 숫자, 배열과 같은 값으로 관리한다는 것이다. 변수에 이러한 UI 관련 값을 보관하고, 리액트의 자바스크립트 코드 흐름에 따라 이를 관리하고, 표현하는 것이 바로 리액트다.
파이버 트리는 사실 리액트 내부에서 두 개가 존재한다. 하나는 현재 모습을 담은 파이버 트리이고, 다른 하나는 작업 중인 상태를 나타내는 workInProgress 트리다. 리액트 파이버의 작업이 끝나면 리액트는 단순히 포인터만 변경해 workInProgress 트리를 현재 트리로 바꿔버린다. 이러한 기술을 더블 버퍼링이라고 한다.
더블 버퍼링은 리액트에서 새롭게 나온 개념이 아니고 컴퓨터 그래픽 분야에서 사용하는 용어다. 그래픽을 통해 화면에 표시되는 것을 그리기 위해서는 내부적으로 처리를 거쳐야 하는데, 이러한 처리를 거치게 되면 사용자에게 미처 다 그리지 못한 모습을 보는 경우가 발생하게 된다. (한 번에 모든 작업을 마무리 해 다 그릴 수 없기 때문이다.) 그래서 이러한 상황을 방지하기 위해 보이지 않는 곳에서 그다음으로 그러야 할 그림을 미리 그린 다음, 이것이 완성되면 현재 상태를 새로운 그림으로 바꾸는 기법을 의미한다.
이 더블 버퍼링은 커밋 단계에서 수행된다.
setState등으로 업데이트가 발생하면 어떻게 될까? 이미 리액트는 앞서 만든 current 트리가 존재하고, setState로 인한 업데이트 요청을 받아 workInProgress 트리를 다시 빌드하기 시작한다. 이 빌드 과정은 앞서 트리를 만드는 과정과 동일하다. 최초 렌더링 시에는 모든 파이버를 새롭게 만들어야 했지만 이제는 파이버가 이미 존재하므로 되도록 새로 생성하지 않고 기존 차이버에서 업데이트된 props를 받아 파이버 내부에서 처리한다.
앞서 언급한 "가급적 새로운 파이버를 생성하지 않는다"가 바로 이것이다.
그러나 현재는 우선순위가 높은 다른 업데이트가 오면 현재 업데이트 작업을 일시 중단하거나 새롭게 만들거나, 폐기할 수도 있다. 또한 작업단위를 나누어 우선순위를 할당하는 것 또한 가능하다.
파이버의 작동 방식과 알고리즘을 이해했다면 가상 DOM에 대해서도 이해하기 쉬워질 것이다. 앞서 언급했듯이 리액트 컴포넌트에 대한 정보를 1:1로 가지고 있는 것이 파이버이며, 이 파이버는 리액트 아키텍처 내부에서 비동기로 이뤄진다. 이러한 비동기 작업과 달리, 실제 브라우저 구조인 DOM에 반영하는 것은 동기적으로 일어나야 하고, 또 처리하는 작업이 많아 화면에 불완전하게 표시될 수 있는 가능성이 높으므로 이러한 작업을 가상에서, 즉 메모리상에서 먼저 수행해서 최종적인 결과물만 실제 브라우저 DOM에 적용하는 것이다.
리액트 파이버는 리액트 네이티브와 같은 브라우저가 아닌 환경에서도 사용할 수 있기 때문에 파이버와 가상 DOM은 동일한 개념은 아니다. 리액트와 리액트 네이티브의 렌더러가 서로 다르다 하더라도 내부적으로 파이버를 통해서 조정되는 과정은 동일하기 때문에 동일한 재조정자를 사용할 수 있게 된다.
가상 DOM과 리액트의 핵심은 브라우저의 DOM을 더욱 빠르게 그리고 반영하는 것이 아니라 바로 값으로 UI를 표현하는 것이다. 화면에 표시되는 UI를 자바스크립트의 문자열, 배열 등과 마찬가지로 값으로 관리하고 이러한 흐름을 효율적으로 관리하기 위한 메커니즘이 바로 리액트의 핵심이다.