일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 리액트 코드분할
- lifting state up
- React
- NextJS
- react router dom v6
- JavaScript
- Front-End
- router dom
- react code splitting
- 타입스크립트
- 프론트엔드
- 상태 끌어올리기
- react rendering
- TypeScript
- 배칭
- 리액트
- rendering
- 자바스크립트
- useMemo
- Next.js
- TS
- 렌더링 동작원리
- mapped types
- 타스
- 자동 배칭
- Interface
- useCallback
- state 최적화
- 렌더링
- 고급타입
- Today
- Total
서녕이네 개발단지
[React] Rendering (렌더링 동작원리)(1) 본문
📄목차
1. 렌더링이란?
1-1. 렌더링 규칙
2. 렌더링 과정(동작 원리)
2-1. DOM에 element 렌더링 하기
2-2. React Element
3. 재조정 (Reconciliation)
3-1. Diffing Algorithm(비교 알고리즘)
1. 렌더링(rendering)이란?
- 현재 props 및 상태를 기반으로 리액트가 컴포넌트에게 UI 영역이 어떻게 보이길 원하는지 설명을 요청하는 프로세스이다.
💡간단히 말해, 코드로 정의된 내용이 실제 브라우저 화면에 그려지는 과정을 의미한다.
리액트는 이때 컴포넌트의 props와 state를 기반으로 UI를 만든다.
❗️ 주의사항 ❗️
1. props의 변화로 인해 렌더링이 이루어지는 것이 아니다.
2. 렌더링이 이루어진 후 props의 변화를 가지고 화면을 그린다.
따라서!! 👉🏻 렌더링 추적 및 최적화는 철저히 state기반으로 이루어져야 한다.
1-1. 렌더링 규칙
리액트 렌더링의 중요한 규칙 중 하나는 렌더링은 '순수' 해야 하고 '부수작용'이 없어야 한다는 것이다.
근데 이는 매우 복잡하고 어려운데, 왜냐하면 대다수의 부수 작용이 왜 일어났는지 뚜렷하지 못하고, 어떤 것도 망가 뜨리지 않기 때문이다.
예를 들어, 엄밀히 말하면 console.log()도 부수작업을 야기하지만, 그 어떤 것도 망가 뜨리지 않는다.
prop이 변경되는 것은 명백한 부수효과 이며, 이는 무언가를 망가 뜨릴 수 있다.
렌더링 중간에 ajax 호출 또한 부수효과를 일으키고, 이는 요청의 종류에 따라서 명백하게 앱에 예기치 못한 결과를 야기할 수 있다.
렌더링을 포함한 다양한 리액트의 라이프 사이클 메서드의 동작과, 어떠한 동작이 '순수' 한지, 혹은 안전한 지를 나타내고 있다.
요약하자면 렌더링 로직이 할 수 없는 것!
- 존재하는 변수나 객체를 변경해서는 안된다.
- Math.random() Date.now()와 같은 랜덤 값을 생성할 수 없다.
- 네트워크 요청을 할 수 없다.
- state를 업데이트
렌더링 로직은
- 렌더링 도중에 새롭게 만들어진 객체를 변경
- 에러 던지기
- 아직 만들어지지 않은 데이터를 lazy 초기화하는 일 (캐시 같은)
등이 가능하다.
2. 렌더링 과정 (동작 원리)
2-1. DOM에 element 렌더링 하기
<div id="root"></div>
이렇게 안에 들어가는 모든 element를 React DOM에서 관리하기 때문에 이것을 '루트(root)' DOM 노드라고 한다.
const root = ReactDOM.createRoot(
document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);
위 코드와 같이 기본적으로 리액트의 렌더링은
우선 DOM 엘리먼트를 ReactDOM.createRoot()에 전달한 다음 ➡️ React Element를 root.render()에 전달하는 과정을 거친다.
👉🏻 코드를 실행하면 화면에 "Hello, world"가 보일 것이다.
+ 설명을 더 하자면~
createElement()를 사용하여 React Element를 만들었다.
이 React Element를 조합(➕)해서 리액트 앱을 만들게 된다. (컴포넌트는 최소한의 빌딩 블락인 리액트 엘리먼트 몇개로 구성된 UI 조각이다).
2-2. React Element
❓React Element란?
- React Element는 쉽게 말해 ~ 리액트 앱을 구성하는 최소한의 빌딩 블락이다.
- 리액트 엘리먼트는 type과 props를 가지는 React 만의 객체이다.
- React.createElement()를 이용해 만들 수 있다.
- type 으로 HTML 태그 이름을 가지고, 그 이외의 특징을 props로 관리하는 객체형태로 정의된다.
🖐🏻 간략한 추가 설명
- 이 React Element는 자바스크립트 객체이며 이것을 DOM으로 렌더링 해주는 역할은 ReactDOM 이 수행한다.
즉, ReactDOM.render()를 통해서 root 엘리먼트에 DOM을 렌더링 하게 된다!!
❗️참고해야 할 점❗️
- React 엘리먼트는 불변객체이다.
- 엘리먼트를 생성한 이후에는 해당 엘리먼트의 자식이나 속성을 변경할 수 없다❌.
- 엘리먼트는 영화에서 하나의 프레임과 같이 특정 시점의 UI를 보여준다.
~~ 지금까지 소개한 내용을 바탕으로 하면 UI를 업데이트하는 유일한 방법은?
=> 새로운 엘리먼트를 생성하고 이를 root.render()로 전달하는 것이다.
⚠️주의⚠️
실제로 대부분의 React 앱은 root.render()를 한 번만 호출한다.
3. 재조정 (Reconciliation)
🙌 리액트에 있어서 재조정(Reconciliation)의 개념을 이해하려면 Virtual DOM의 이해가 필요하다. (전 포스팅에 가상돔 설명 참조.)
❓재조정이란?
- 리액트는 선언적 API를 제공하기 때문에 리액트 사용자는 렌더링 작업을 함에 있어서 매번 무엇이 바뀌었는지를 걱정할 필요가 없다.
- 하지만!! 내부에서는 기존의 가상 돔과 변경사항이 생긴 가상 돔의 비교작업이 이루어지는데
👉🏻이 과정을 Reconciliation(재조정) 이라고 말한다.
이 과정을 거치려면, 실제로는 모든 DOM 트리를 순회하면서 탐색 및 변경하는 과정을 거쳐야 한다.
하지만 이런 모든 과정을 거친다면 최첨단의 알고리즘을 이용해도 O(n^3)의 시간복잡도를 가진다고 한다.🥲
따라서! 리액트는 조금은 다른 휴리스틱한 알고리즘을 이용해, 시간복잡도를 O(n)까지 줄이는 방식을 택한다.
참고❗️
v16이상 부터는 React Fiber 라는 새로운 알고리즘을 적용해 기존의 Reconciliation 알고리즘에서 발생하는 애니메이팅에 대한 부분을 개선했다고 한다.
브라우저에 렌더링을 할 때 어떻게 기존의 컴포넌트와 변경이 되었는지 확인하기 위해 리액트에서
* Diffing Algorithm(비교 알고리즘)을 사용하여 이 알고리즘을 통해 컴포넌트의 갱신한다.
리액트는 아래의 2가지 가정을 기반으로 O(n)의 시간복잡도를 가지는 휴리스틱 알고리즘을 구현했다.
- 서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어 낸다.
- 개발자가 key prop을 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해 줄 수 있다.
3-1. Diffing Algorithm(비교 알고리즘)
- 두 개의 트리를 비교할 때, React는 두 엘리먼트의 루트(root) 엘리먼트부터 비교한다.
이후의 동작은 루트 엘리먼트의 타입에 따라 달라진다.
DOM 엘리먼트의 타입이 다른 경우
<div>
<Counter />
</div>
<span>
<Counter />
</span>
👉🏻 이전 트리를 버리고 완전히 새로운 트리를 구축 (비효율적이다)
DOM 엘리먼트의 타입이 같은 경우
<div className="before" title="stuff" />
<div className="after" title="stuff" />
// 변경된 속성들에 대해서만 갱신
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />
// 스타일 또한, 변경 사항이 있는 속성만 업데이트 (color 속성만 업데이트함)
참고
https://www.nextree.io/riaegteu-rendeoring-mic-coejeoghwa/
https://eastflag.co.kr/react/script-tag/react-element/
https://ko.legacy.reactjs.org/docs/rendering-elements.html#gatsby-focus-wrapper
https://programming119.tistory.com/240
https://yceffort.kr/2022/04/deep-dive-in-react-rendering#리액트-렌더링-규칙
'프론트엔드 > React' 카테고리의 다른 글
[React] Code Splitting (코드 분할) (0) | 2023.06.11 |
---|---|
[React] Lazy Loading (지연 로딩), Suspense (서스펜스) (0) | 2023.06.11 |
[React] 렌더링 최적화 (0) | 2023.06.11 |
[React] Rendering (렌더링 동작원리)(2) (0) | 2023.06.10 |
[React] Virtual Dom(가상 돔) (2) | 2023.06.09 |