본문 바로가기
FE/react

[React] 리액트 렌더링 과정

by s0ojin 2024. 1. 14.

 

 

본 글은 <모던 리액트 DEEP DIVE>도서의 내용을 바탕으로 작성되었습니다.

 

 

 

리액트 렌더링이란?


브라우저 렌더링: HTML과 CSS리소스를 기반으로 웹페이지에 필요한 UI를 그려내는 과정

리액트 렌더링: 브라우저가 렌더링에 필요한 DOM 트리를 만드는 과정

 

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

 

리액트 렌더링이 일어나는 경우


  • 최초 렌더링
  • 리렌더링
    • 클래스형 컴포넌트의 setState가 실행되는 경우
    • 클래스형 컴포넌트의 forceUpdate가 실행되는 경우
    • 함수형 컴포넌트의 useState()의 두번째 배열요소인 setter가 실행되는 경우
    • 함수형 컴포넌트의 useReducer()의 두번째 배열요소인 dispatch가 실행되는 경우
    • 컴포넌트의 key props가 변경되는 경우
    • props가 변경되는 경우
    • 부모 컴포넌트가 렌더링되는 경우

 

리액트 렌더링 과정


1. 렌더링 프로세스가 시작되면 리액트는 컴포넌트 루트부터 아래로 내려가며 업데이트가 필요하다고 지정돼 있는 컴포넌트를 찾는다.

2. 업데이트가 필요한 컴포넌트를 만나면 클래스형 컴포넌트는 클래스 내부의 render() 함수를 실행하게 되고, 함수형 컴포넌트의 경우에는 FunctionComponent() 그 자체를 호출하고, 그 결과물을 저장한다.

3. 렌더링 결과물은 JSX문법으로 구성되어 있고, 자바스크립트로 컴파일되면서 React.createElement()를 호출하는 구문으로 변환된다. 이때 createElement()는 자바스크립트 객체를 반환한다.

4. 이 렌더링 결과물을 수집하여, 리액트의 새로운 트리인 가상DOM과 비교해 실제 DOM에 반영하기 위한 모든 변경 사항을 차례차례 수집한다. (Reconciliation)

 

 

리액트 렌더 과정은 크게 렌더단계와 커밋단계로 나눌 수 있다.

 

 

렌더단계

  • 컴포넌트를 렌더링하고 변경사항을 계산하는 모든 작업 
  • 렌더링 프로세스에서 컴포넌트를 실행하여 이 결과와 이전 가상 DOM을 비교하는 과정을 거쳐 변경이 필요한 컴포넌트를 체크하는 단계
  • type, props, key 중 하나라도 변경된 것이 있다면 변경이 필요한 컴포넌트로 체크된다.

커밋단계

  • 렌더 단계의 변경사항을 실제 DOM에 적용해 사용자에게 보여주는 단계
  • 이 단계가 끝나야 비로소 브라우저 렌더링이 발생한다.

 

리액트가 먼저 DOM을 커밋 단계에서 업데이트한다면 이렇게 만들어진 모든 DOM 노드 및 인스턴스를 가리키도록 리액트 내부의 참조를 업데이트한다. 그다음 생명주기 개념이 있는 클래스형 컴포넌트에서는 componentDidMount, componentDidUpdate메서드를 호출하고, 함수형 컴포넌트에서는 useLayoutEffect 훅을 호출한다. 

 

여기서 중요한 사실은 리액트의 렌더링이 일어난다고 해서 무조건 DOM 업데이트가 일어나는 것은 아니라는 것이다. 렌더링을 수행하여 변경사항을 감지했으나 변경사항이 없다면, 커밋 단계는 생략될 수 있다. 즉, 리액트의 렌더링은 가시적인 변경이 일어나지 않아도 발생할 수 있다. 

 

리액트 동시성 렌더링(Concurrent Rendering)


렌더와 커밋 단계로 이뤄진 리액트 렌더링은 항상 동기적으로 작동했다. 따라서 렌더링 과정이 길어질수록 앱의 성능저하로 이어지고, 결과적으로 그 시간만큼 브라우저의 다른작업을 지연시킬 가능성이 있다. 이는 렌더링 프로세스의 특징을 생각해보면 당연한데, 만약 순서가 보장되지 않는 비동기 방식으로 이뤄질 경우 사용자가 하나의 상태에 대해 여러 다른 UI를 보게될 수 있기 때문이다. 

그러나 때로는 비동기 렌더링이 유효할 수 있는데, 가령 B컴포넌트의 렌더링 작업이 무거워 상대적으로 빠르게 렌더링 할 수 있는 A컴포넌트라도 변경해서 보여줄 수 있다면 그것이 더 좋은 방향일 것이다. 이처럼 의도된 우선순위로 컴포넌트를 렌더링해 최적화할 수 있는 비동기 렌더링, 이른바 동시성 렌더링이 리액트 18에서 도입되었다.

 

자바스크립트는 싱글스레드인데 어떻게 동시성 렌더링이 가능할까?
여러 작업을 작은 단위로 나눈 뒤 작업들 간의 우선순위를 정해 작업을 번갈아 수행하는 것이다.
작업 간의 전환이 매우 빠르게 이루어져서 동시에 여러 작업이 수행되는 것처럼 보이게 되는 것.

 

References


댓글