리액트의 렌더링 w/가상돔, Fiber

에구마·2024년 6월 26일
2

React

목록 보기
5/5

리액트의 특징이자 장점은 가상DOM이지 않을까.

  • 가상돔이 무엇인가?
    실제 DOM의 복사본 정도의 개념이고, 화면에 보여질 DOM 계산을 브라우저가 아닌 메모리에서 함으로써 렌더링 발생을 최소화 하는데 사용된다.
  • 돔보다 빠른가?
    그렇지만은 않다.

리액트 렌더링


파이버를 알아보기 전, 리액트의 렌더링 과정부터 알아본다.

흔히 HTML→CSS→레이아웃→페인트의 과정을 가지는 브라우저의 렌더링과는 다르다.

리액트 렌더링은 리액트 어플리케이션 트리 안에 있는 모든 컴포넌트들이 현재 자신들이 가지고 있는 props와 state의 값을 기반으로 어떻게 UI를 구성하고 어떤 DOM결과를 브라우저에 제공할 것인지 계산하는 일련의 과정이다.

리액트에서 렌더링은 언제 일어나는가?

  • 최초 렌더링
  • 리렌더링 (최초 렌더링 제외한 모든 렌더링 경우임, 함수컴포넌트의 경우만 적었음)
    • 상태가 변경된 경우 (=useState의 setter가 실행됨)
    • useReducer의 dispatch가 실행된 경우
    • 컴포넌트 key props가 변경된 경우
    • props가 변경된 경우
    • 부모 컴포넌트가 리렌더링된 경우 (memo로 막을 순 있음)

리액트의 렌더링은 어떻게 일어나는가?

  • 컴포넌트 렌더링
    컴포넌트의 루트에서부터 아래로 내려가며 업데이트가 필요하다고 지정된 컴포넌트 찾음 → 그 컴포넌트의 reder() 혹은 return문의 결과인 JSX를 저장 → 그 JSX는 컴파일되면서 React.createElement()를 호출하는 구문으로 변환되고 이는 브라우저의 UI구조를 설명할 수 있는 일반적인 자바스크립트 객체를 반환

  • 엘리먼트 렌더링

    • 재조정
      객체로 변환한 결과물들을 수집한 다음, 가상돔과 비교해 실제돔에 반영할 모든 변경사항을 수집

    • DOM 업데이트
      재조정 과정이 끝나면 모든 변경 사항을 하나의 동기 시퀀스로 DOM에 적용해 변경된 결과물이 보이도록 한다.

이 과정을 두단계로 나눈다. 렌더 단계(컴포넌트렌더링~재조정)와 커밋 단계(DOM업데이트)

  • 렌더 단계
    컴포넌트렌더링 ~ 재조정까지의 단계로, 변경사항을 계산하는 작업이다.
    컴포넌트 return문 결과와 이전 가상 돔 비교하여 변경 컴포넌트를 체크한다. 이 때 type, props, key 중 하나라도 변경되었다면 변경 컴포넌트로 체크

  • 커밋 단계
    변경 사항을 실제 DOM에 적용해 사용자에게 보여주는 과정
    커밋 단계가 마친 이후에 비로소 ‘브라우저 렌더링’ 시작
    DOM 업데이트 이후에 라이프사이클 메소드와 useEffect도 실행
    변경 사항이 있어 렌더링이 일어났으나, 커밋은 없었을 수 있음. 즉, DOM 업데이트가 일어나지 않은거고 화면에 가시적인 변경은 안일어남


리액트 파이버(Fiber)


가상돔과 실제돔을 비교해 변경 사항을 찾는 작업을 “재조정(reconcilations)”이라고 했다.

여기서 그 변경사항에 관련된 정보를 가지고 있는게 “파이버”이다.
파이버는 파이버 재조정자가 관리하고 파이버 재조정자는 이 파이버를 기준으로 화면에 렌더링을 요청한다.

React16이전까진 Stack 재조정 아키텍쳐를 사용했다. 한번 작업이 시작되면 동기적으로 기다려야 하는 문제가 있었다. 그래서 리액트 파이버가 도입되었다. 리액트 파이버는 모든 과정이 비동기적으로 일어난다.

파이버는 다음 기능이 가능하다.

  • 작업을 작은 단위로 쪼개어 우선순위를 부여 가능
  • 작업을 일시 중지하고 나중에 다시 시작 가능
  • 이전 작업을 다시 재사용하거나, 필요 없는 작업 폐기 가능

파이버는 단순한 자바스크립트 객체로 구성되어있다. 내부 요소엔 tag, type, child, sibling 등이 있다.

파이버 트리

파이버 트리는, 파이버를 노드로 갖는 트리이다. 가상DOM으로 생각할 수 있지만 동일한것은 아니다.

👩🏻‍💻 React Element를 fiber노드로 확장해 가상DOM을 이루게 하는거라고 여겨보자.
즉, fiber란 가상돔의 노드 객체가 된다!

파이버트리는 두 개가 존재한다.

  • 현재 모습의 파이버 트리
  • 작업 중인 상태를 나타내는 workInProgress 트리

작업 완료 시 포인트를 workInProgress로 옮겨 이를 현재 트리로 바꾼다. 이게 “더블 버퍼링”이라 한다.

파이버 작업 순서

JSX를 읽어 화면에 그리고 변경사항에 따라 새로 그리는 과정은 다음과 같다.

  1. 컴포넌트마다 beginWork()가 실행되며 파이버 작업 수행.
    더 이상 자식 없는 파이버 까지 트리 형식으로 들어감
  2. completeWork()를 통해 파이버 작업 완료. 형제가 있다면 그다음은 형제로 넘어감
  3. 1,2를통해 형제,자식 까지 완료 되었다면 return을 통해 자신의 작업 완료

! 여기서 setState 등 업데이트가 발생되었다 !

  1. setState로 인한 업데이트 요청을 받아 workInProgress 트리를 빌드
  2. 이 트리가 렌더링되어 UI에 반영되면 current가 workInProgress가 된다(더블버퍼링)

정리하면,

파이버 작동은 비동기로 발생한다. (우선순위에 따라)
실제 돔을 업데이트 하는 작업은 한번에 일어나고(=동기적), 브라우저 이벤트루프 내에서 동기적으로 발생한다.

가상돔(파이버)를 사용하는 이유는, 변경이 많아 화면에 불안전하게 표시될 가능성을 막기 위해, 먼저 메모리상에서 변경을 수행하고 최종 결과만 실제 브라우저 돔에 적용하기 위함이다.


마치며..

리액트는 가상돔을 쓴다, 가상돔과 변경사항을 비교하여 돔에 반영한다로 알고있던 부분을 자세히 공부해봐서 의미 있었다.
훅을 조금 더 알아봐야겠다! 훅에서 상태 변경 -> 리렌더링 과정을 크게 묶어 이해해야겠다




그림 출처 및 참고
https://velog.io/@mogulist/understanding-react-rerender-easily
https://medium.com/@ian-white/jsx-가상-dom과-리액트-파이버-2772f24ede31
https://medium.com/@sht02048/생각보다-더-섬세한-리액트-렌더링-과정-feat-리액트-파이버-44075084381a
https://velog.io/@mogulist/understanding-react-rerender-easily#3-2가지-렌더링과-2가지-단계phase

profile
코딩하는 고구마 🍠 Life begins at the end of your comfort zone

0개의 댓글