랜더링이란?
브라우저에서의 랜더링: HTML,CSS 리소스를 기반으로 웹페이지에 필요한 UI를 그리는 과정
리액트에서의 랜더링: 브라우저가 랜더링에 필요한 DOM트리를 만드는 과정
→ 두개를 혼동하지 않도록 하자.
그렇다면 리액트에서 랜더링이 어떻게 일어나고, 주의할 점은 무엇인가
리액트의 랜더링
정의
리액트에서의 랜더링: 리액트 어플리케이션 트리 안에 있는 모든 컴포넌트들이 현재 자신들이 가지고 있는 props와 state의 값을 기반으로 어떻게 UI를 구성하고 이를 바탕으로 어떤 DOM 결과를 브라우저에 제공할 것인지 계산하는 일련의 과정
랜더링은 언제 발생하는가?
리액트에서 랜더링이 발생하는 시나리오
- 최초 렌더링
- 처음 애플리케이션 진입 시 리액트가 브라우저에 랜더링 결과물을 제공
- 리렌더링
- 최초 랜더링 이후 발생하는 모든 랜더링
- setState실행
- forceUpdate 실행
- useState() setter 실행
- useReducer() dispatch 실행
- 컴포넌트 key props 변경
- props 변경
- 부모 컴포넌트 리랜더링 → 자식컴포넌트 리랜더링
- 최초 랜더링 이후 발생하는 모든 랜더링
어떤 과정을 거쳐 렌더링 되는가?
- 랜더링 프로세스 시작
- 컴포넌트 루트에서부터 업데이트가 필요한 모든 컴포넌트를 찾는다
function Hello() {
return (
<TestComponent a={35} b="yceffort">
안녕하세요
</TestComponent>
);
}
- 함수 → FunctionComponent() 호출 후 그 결과물 저장 (JSX)
- 클래스 → 클래스 내부의 render() 함수 실행
- JSX가 JS로 컴파일되면서 React.createElement()를 호출하는 구문으로 변환
function Hello() {
return React.createElement(
TestComponent,
{ a: 35, b: 'yceffort' },
'안녕하세요'
);
}
- createElement는 브라우저의 UI구조를 설명할 수 있는 JS객체를 반환
{type: Testcomponent, props: ta: 35, b: "yceffort", children : "안녕하세요"}}
다음과 같이 각 컴포넌트의 랜더링 결과물을 수집한 다음, 새로운 트리인 가상DOM과 비교해 실제 DOM에 반영하기 위한 모든 변경 사항을 수집한다. (재조정)
재조정이 끝나면 모든 변경 사항을 하나의 동기 시퀀스로 DOM에 적용해 변경된 결과물이 보이게 된다. 이 단계가 바로 커밋 단계이다.
랜더 & 커밋
리액트의 랜더링 프로세스는 랜더와 커밋 단계로 나뉜다.
랜더
컴포넌트를 랜더링하고 변경 사항을 계산하는 모든 작업이다.
→ 컴포넌트를 실행해 이 결과와 이전 가상 DOM을 비교하는 과정을 거쳐 변경이 필요한 컴포넌트를 체크
커밋
랜더 단계의 변경 사항을 실제 DOM에 적용해 사용자에게 보여주는 과정
리액트의 랜더링이 일어난다고 해서 무조건 DOM 업데이트가 일어나는 것은 아니다
랜더링을 했으나 변경사항이 감지되지 않으면 커밋 단계는 생략된다. 즉 랜더링이 되어도 브라우저의 DOM 업데이트는 일어나지 않을 수도 있다.
비동기적 랜더링
랜더링이 비동기 식으로 이뤄질 경우 사용자는 하나의 상태에 대해 여러 가지 다른 UI를 보게 될 것이다. 그러므로 어찌보면 당연히 리액트의 랜더링은 항상 동기식으로 작동한다.
따라서 랜더링 과정이 길어지먄 성능 저하로 이어진다.
하지만 어떤 컴포넌트 랜더링 작업이 너무 무거을 경우 의도된 우선순위로 상대적 빠르게 랜더링할 수 있는 컴포넌트를 먼저 랜더링하여 보여줄 수 있는 비동기 랜더링이 리액트 18에서 도입됐다.
이를 동시성 랜더링이라고 한다.
동시성 랜더링은 랜더링 중 랜더 단계가 비동기로 작동해 특정 랜더링의 우선순위를 낮추거나, 중단하거나, 재시작하거나, 포기할 수도 있다.