본문 바로가기
코딩 정보/React

[React][Virtual Dom][Fiber]에 대해 알아보자

by 꽁이꽁설꽁돌 2024. 9. 16.
728x90
반응형

목차

     

    이전걸 참고하면 이해하는데 도움이 됩니다.

    참고

    https://be-senior-developer.tistory.com/189

     

    브라우저의 랜더링에 대해 자세히 알아보자

    목차 브라우저의 정의웹상에 존재하는 페이지들의 HTML 언어를 해석해서 사용자의 컴퓨터 화면에 출력해 주는 프로그램그렇다면 웹브라우저의 구조는 어떻게 되어있을까? 다음그림을 통해 쉽

    be-senior-developer.tistory.com

     

    virtual Dom이란?

     

    DOM을 추상화한 가상의 객체로, Virtual DOM은 Real DOM 객체와 동일한 속성을 가지고 있는 가벼운 사본이다.

     

    주요한 특징으로는 다음과 같다.

    • React에는 모든 DOM 객체에 대응하는 가상의 DOM 객체가 있다.
    • React는 실제 DOM 객체에 접근하여 조작하는 대신 이 가상의 DOM 객체에 접근하여 변화 전과 변화 후를 비교하고 바뀐 부분만 렌더링한다.
    • Virtual DOM은 가상의 UI 요소를 메모리에 유지시키고, 그 유지시킨 가상의 UI 요소를 ReactDOM과 같은 라이브러리를 통해 실제 DOM과 동기화시킨다.(Virtual DOM 객체는 화면에 표시되는 내용을 Real DOM 객체처럼 직접 변경하지 않음)
    • Real DOM은 실제 브라우저 화면을 그리기 때문에 조작 속도가 느리지만, Virtual DOM은 실제로 브라우저 화면에 그리는 것이 아니기 때문에 조작 속도가 훨씬 빠르다.

     

    재조정(Reconciliation)

    리액트에서 가상돔을 실제 DOM에 반영하는 과정을 재조정이라고 한다.

    이때 실제 DOM과 가상 DOM을 효율적으로 비교하여 랜더링하기 위해  Diffing Algorithm이라는 것을 사용하게 된다.

    그렇다면 Diffing Algorithm이 무엇일까?

     

     

    Diffing Algorithm

    해당 컴포넌트 내에 스테이트가 변경된 경우에는, 리액트는 해당 컴포넌트를 dirty 하다고 표시하고 batch에 추가합니다. (물론 앞으로 쓰게 될 redux와 같은 store를 이용하게 되면, 컴포넌트 단위가 아닌 root 노드(App component)에 dirty 마크가 찍히게 됩니다.)

     

    Virtual Dom 엘리먼트와 실제 브라우저에 등록되어있는 DOM 엘리먼트를 비교 및 순회하며 dirty 체크된 엘리먼트들을 처리합니다.

     

    그 과정에서 해당 엘리먼트의 태그 혹은 컴포넌트가 변경된 경우라면 해당 노드를 포함한 하위의 모든 노드를 언마운트(제거)한 뒤에 새로운 virtualDom으로 대체합니다.

     

    컴포넌트의 변경 예시

    <div>
    	<Counter />
    </div>
    
    //부모 태그가 div에서 span으로 바뀝니다.
    <span>
    	<Counter />
    </span>

     

    속성 값만 변한 경우에는 속성 값만 업데이트합니다.

     

    속성값 변경 예시

    <div className="before" title="stuff" />
    
    //기존의 엘리먼트가 태그는 바뀌지 않은 채 className만 바뀌었습니다.
    <div className="after" title="stuff" />

     

    이러한 변경 혹은 업데이트가 모두 마무리 된 후에(batch에 쌓인 모든 것들을 처리한 후에) 한 번 실제 돔에 이 결과를 업데이트 합니다.

     

    그렇다면 여기서 의문이 듭니다. dom, virtual dom, render 이것들을 순회 하면서 O(n^3)의 시간복잡도가 아니라 어떻게 O(n)의 시간 복잡도로 이러한 작업을 할 수 있는 것일까?

     

    바로 heuristics Algorithm 덕분이다. 그렇다면 또 이건 무엇일까?

     

     Heuristics Algorithm

    불충분한 시간이나 정보로 인하여 합리적인 판단을 할 수 없거나, 체계적이면서 합리적인 판단이 굳이 필요하지 않은 상황에서 사람들이 빠르게 사용할 수 있게 보다 용이하게 구성된 간편 추론의 방법이다.

     

    중요하지 않은 정보들은 고려하지 말고 중요한 것들만 고려해서 최선의 값을 찾아내는 방법이다.

    그 중 중요하게 생각하는 정보중 하나는 key이다.

     

    아래 코드를 보면 key속성을 통해 2014라는 자식 엘리먼트가 새롭고 생겼고, 2015, 2016이라는 키를 가진 엘리먼트는

    그저 위치만 이동했다는 것을 알게 된다.

    <ul>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul>
    
    <!--key가 2014인 자식 엘리먼트를 처음에 추가한다.-->
    <ul>
      <li key="2014">Connecticut</li>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul>

     

    자 이렇게 장황하게 설명해서 끝난 줄 알았으니 아직 끝나지 않았다!

     

     

    일반적으로 Reconciler and Renderer 과정은 매우 빠르게 일어나기 때문에 보통의 경우라면 느끼기 어렵지만 연속적인 애니메이션과 많은 DOM조작이 필요한 경우 콜 스택이 모두 처리될때 까지 메인 스레드는 아무작업을 할 수 없게 되니 버벅임을 느낄 수 있게 된다. 이러한 이유에서 React v16 이전의 reconciler 모듈은 Stack Reconciler라는 모듈이었으나 이후에 fiber Reconciler로 바뀌었다.

     

     

    Fiber Reconciler

    • React element와 fiber는 매우 유사하지만 중요한 차이점은 React element는 매번 다시 생성 되지만 React Fiber는 가능한 자주 재사용된다.(초기 마운트 시 Fiber가 생성되며 그 후에는 대부분 재사용된다.)
    • React는 Fiber를 처리할때 마다 우선순위에 따라 다음 작업을 처리할 것 인지 예약할 것 인지 정할 수 있다.
    • 어떤 작업이 애니메이션과 같은 높은 우선순위를 가지고 있다면 requestAnimationFrame 함수를 통해 우선순위가 높은 함수를 예약할 수 있다.
      또는 requestIdleCallback 함수를 통해 유휴 기간동안 호출한 우선순위가 낮은 함수를 예약할 수 있다.(두 함수를 지원하지 않는 브라우저의 경우 폴리필을 제공한다.)
    • alternate 속성은 이전 작업 current Fiber와 workInProgress Fiber가 연결되어있는 한쌍으로 Fiber가 재사용되기 위해서 매우 중요한 속성 ( 다음 내용에서 다룬다. )
    • Fiber의 속성에 child, sibling, return이 있으며 각각 자식Fiber, 형제Fiber, 부모Fiber가 저장되어 있어 자식요소가 없다면 형제요소를 탐색하고 형제가 없다면 부모요소를 탐색하는 DFS 알고리즘으로 작동한다.

     

    current 와 workInProgress 트리

    Fiber는 current와 workInProgress 두가지 트리를 가지는데 current 트리는 현재 화면에 있는 것으로 React가 변경 하면 안정성을 보장 할 수 없기 때문에 복사본인 workInProgress 트리를 만들어서 작업하게 된다.

     

    랜더 이후 커밋을 할 경우 workInProgress 트리가 현재(current)의 트리가 된다.

    반응형