목차
· 트리거 단계 (Trigger Phase)
· 렌더 단계 (Render Phase)
· 커밋 단계 (Commit Phase)
리액트 라이프 사이클에 대한 부분을 대강 알고있지만, 누군가 설명을 해보라고 했을 때 설명을 진행하긴 하지만 버벅이곤 합니다. 이런 버벅이는 증상이 아직 익숙하지 않다는 증거라는 생각에 오늘은 커밋 페이즈, 렌더 페이즈에 대한 부분들을 포스팅해보려고 합니다.
리액트 렌더링 단계에는 렌더 단계(Render Phase)와 커밋 단계(Commit Phase)가 있는데 렌더 단계에서는 화면에 그릴 것들을 파악하고, 커밋 단계에서는 직전에 파악한 것들을 화면에 적용합니다. 리액트가 초기 렌더링 동작과, 리렌더링시에 각 단계에서 어떤 것들을 수행하는지 살펴봅니다.
잠깐 정리를 먼저 해보겠습니다 🫨
· 리액트 렌더링은 렌더 단계와 커밋 단계로 나눌 수 있어요
· 렌더 단계는 재조정 단계를 거쳐 가상 DOM요소의 변화를 감지하고 필요한 업데이트를 결정하는 단계예요
· 커밋 단계에서는 렌더 단계에서 결정된 변경사항들을 실제 DOM에 반영해요
트리거 단계 (Trigger Phase)
컴포넌트가 그려지기 위해서는 어떠한 액션, 트리거가 필요합니다. 사용자가 서비스에 접속을 한다거나, 상품 목록의 필터 버튼을 클릭했을 떄와 같은 트리거를 의미합니다. 리액트에서의 트리거 상황에 경우 2가지 정도로 크게 확인할 수 있습니다.
- 사용자가 페이지에 처음 방문했을 때 - 초기 렌더
- 어떠한 상태가 업데이트되었을 때 - 리렌더
트리거 단계는 초기 렌더 또는 다음 렌더 (리렌더)를 알리는 동작이자, 단계라고 볼 수 있습니다.
1. 트리거 단계 - 초기 렌더
사용자가 처음 사이트에 방문을 하게 된다면, 리소스를 서버에 요청하고 앱이 실행됩니다. 엔트리 파일에서 ReactDOM의 render() 메소드를 호출하고 루트 컴포넌트를 화면에 그리는 동작을 진행합니다.
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<App/>);
2. 트리거 단계 - 리렌더
앱이 실행되고 다음 렌더는 상태 업데이트 함수가 호출되어 상태가 변경되었을 때 발생을 합니다. 상태 업데이트 함수가 호출되면 리액트는 렌더링 해야하는 부분을 큐에 입력합니다. 그리고 큐를 확인하고 순차적으로 렌더링 작업을 수행합니다. 한번의 렌더 사이클에서 하나의 상태 업데이트를 처리하는 것은 많은 연산과 리소스를 많이 필요로하기 때문에 한번의 DOM 업데이트를 통해서 처리하려고 시도합니다.
렌더 단계 (Render Phase)
렌더가 트리거되면 단계로 넘어가 DOM에 그려질 요소들을 파악하는 과정을 진행합니다. 요소들을 파악하는 단계 또한 초기 렌더와 리렌더로 구분을 할 수 있습니다.
- 초기 렌더에서 렌더 단계는 render() 메소드의 루트 컴포넌트를 호출합니다.
- 리렌더에서 렌더 단계는 상태 업데이트가 발생한 컴포넌트를 호출합니다.
리액트는 컴포넌트를 호출하고, 모든 자식 요소들을 재귀적으로 처리하여 트리의 구성 요소들을 파악합니다. 여기서 재귀적으로 처리한다는 것은 컴포넌트를 호출했을 때 리턴 값으로 컴포넌트가 반환되면 그 반환된 컴포넌트를 다시 호출하는 과정을 의미합니다.
함수가 연쇄적으로 호출될 때 내부의 JSX는 React.createElement() 함수로 JSX를 리액트 요소로 변환하는데, 재귀적으로 생성된 리액트 요소들은 UI의 구조를 나타내는 객체이자 DOM의 가상 복사본인 가상 DOM으로 유지됩니다. 트리를 따라 호출을 반복하다가 최종적으로 더 이상 컴포넌트가 반환되지 않으면 비로소 가상 DOM 트리가 그려집니다. 첫 렌더 시 가상 DOM과 실제 DOM이 동기화되고 추후 렌더링에는 렌더마다 새로운 가상 DOM을 만듭니다.
1. 렌더 단계 - 초기 렌더
초기 렌더에는 브라우저가 엔트리 파일을 읽으면서 루트 요소부터 파악을 진행합니다.
function App() {
return (
<main>
<h1> Hello React </h1>
<Item/>
<Item/>
</main>
)
}
function Item() {
return <div> This is Item </div>
}
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<App/>);
위의 코드에서 render() 메소드가 호출이 되면 리액트는 createElement()를 통해 <main>, <h1>, <div> 태그에 대한 HTML 요소들을 생성합니다.
2. 렌더 단계 - 리렌더
리렌더에서 렌더 단계는 이전에 생성한 가상 DOM 트리와 새로 만든 가상 DOM 트리를 비교하여 실제 DOM에 반영할 변경 사항들을 파악하는데, 최소한의 변경 사항만 파악하기 위해 상태 업데이트가 발생한 컴포넌트를 호출하고 새로운 가상 DOM 트리를 생성합니다. 리액트가 이전 렌더와 다음 렌더의 변화를 비교하는 과정을 재조정(Recognition)이라고 합니다. 리렌더가 발생하면 리액트는 렌더 간 어떤 요소와 속성들이 변했는지 파악하고, 이 정보를 커밋 단계에서 사용합니다.
커밋 단계 (Commit Phase)
커밋 단계에서는 직전 렌더 단계에서 두 가상 DOM 트리 간 변화를 실제 DOM에 적용하는 단계입니다. 커밋 단계 또한 초기 렌더와 리렌더에 다르게 동작을 합니다.
- 초기 렌더에서 커밋 단계는 렌더 단계에서 파악한 DOM 노드들을 DOM에 반영합니다.
- 리렌더에서 커밋 단계는 렌더 간 발생한 최소한의 변경 사항들을 DOM에 반영합니다.
렌더 단계에서 계산한 변경 사항들을 실제 DOM에 적용할 때 적용이라는 것은 DOM 노드를 새로 생성, 수정 또는 삭제하여 새로운 컴포넌트 트리와 동기화하는 과정을 의미합니다. DOM의 조작이 발생하면 전체 UI를 다시 렌더링하는 것처럼 보이지만 실제로는 변경된 DOM 노드만 파악해서 최소한의 변경만 실제 DOM에 반영합니다.
레퍼런스
'개발적인' 카테고리의 다른 글
Reduce로 코드 클린하게 만들기 (0) | 2024.07.02 |
---|---|
분리된 파일의 tanstack mutate 메소드를 컴포넌트 안에서 사용하기 (0) | 2024.06.28 |
Vite 환경에서 구글 애널리틱스 3분만에 적용하기 (1) | 2024.06.12 |
타입스크립트 딥다이브 (0) | 2024.05.31 |
Next 13에 Vanila Extract 적용하기 (0) | 2024.05.31 |
댓글