엘리먼트 렌더링

Yeom Jae Seon·2021년 1월 30일
1

React공식문서 공부

목록 보기
2/11
post-thumbnail

들어가기 전에

저번 시간에 JSX에 대해서 공부했다.
복습하자면 JSXReact.CreateElement()와 같은 놈이고 React.CreateElement()React 엘리먼트라는 객체를 리턴한다.
그래서 리액트에서는 JSX를 객체로 인식한다.
그리고 React는 엘리먼트를보고 DOM을 구성하여 최신 UI상태를 유지한다까지 맛만 보고 끝났다.

즉, React Element, 엘리먼트는 어떻게 화면을 구성해야할지가 적혀있는 설명서(레시피)라고 생각하면 된다

이젠 이 엘리먼트가 좀더 자세히 어떤식으로 렌더링 되는지 알아보자.

엘리먼트

엘리먼트 : React 앱의 가장 작은 단위이다.
엘리먼트는 화면에 표시할 내용을 기술한다.(설명서, 레시피)

const element = <h1>안뇽</h1>

(콘솔에 찍으면)

콘솔에서도 보기와같이 이 React.createElement()가 리턴한 객체 즉, 리액트 엘리먼트는 객체인걸 알수 있다.

React 엘리먼트는 일반 객체이며 방금 내가한것같이 매우 간단하게 생성할수 있다.
React DOM은 이 React엘리먼트와 일치하도록 DOM을 업데이트한다.
즉, React는(React DOM)은 React 엘리먼트를 보고 React 엘리먼트에 맞게 DOM을 업데이트 한다는 뜻이다.

조금 두루뭉실하지만 여기까지는 'React는 (React DOM이란 아이는) React Element를 보고 React Element와 DOM을 일치시켜서 DOM을 업데이트한다' 까지만 이해하고 더자세한건 아래에서 보자.

  • React는 React 엘리먼트를 보고 DOM을 업데이트하여 UI 최신상태를 유지한다.

DOM에 엘리먼트 렌더링하기

DOM과 React Element는 React가 일치시킨다고 알고있다.
그런데 HOW?? 어떻게??

CRA로 react app을 만들어본사람은 알겠지만 public/index.html<div id="root></div>라는 태그가 존재한다.

결론부터 말하면 이 div태그에 들어가는 모든 React 엘리먼트를 React DOM에서 관리하기 때문에 이 <div>루트 DOM 노드 라고한다.

일반적으로 이 <div>와 같은 루트 DOM 노드는 하나만 존재하는데 꼭 하나만 존재할필요 없다.
이건 자명한 사실임. 그냥 여러 태그있으면 여기에 React 엘리먼트들을 넣으면 루트 DOM 노드는 여러개겠지?

  • 루트 DOM 노드가 여러개인 상황
    (ReactDOM.render()에 대해선 바로 아래에서 다룰거니 자세힌 보지말고 그냥 루트 DOM노드가 여러개가 가능하다 정도만 보면 된다.)
//index.html
  <div id="root"></div>
  <div id="root2"></div>
//index.js
import React from "react";
import ReactDOM from "react-dom";

const element = <div>안뇽</div>;
ReactDOM.render(element, document.getElementById("root"));

ReactDOM.render(element, document.getElementById("root2"));

이제는 어떤식으로 이 루트 DOM NodeReact Element를 연결시키느냐? 즉, 루트 DOM NodeReact Element를 어떻게 넣는지를 알아볼 시간이다.

React 엘리먼트를 루트 DOM Node에 넣으려면 ReactDOM.render()라는 함수를 이용하면 된다.!

import React from "react";
import ReactDOM from "react-dom";

const element = <div>안뇽</div>;
ReactDOM.render(element, document.getElementById("root"));

이런식으로 ReactDOM.render() 인자에 리액트 엘리먼트와 루트 DOM 노드를 넣으면 React는 React Element를 보고 DOM을 구성하게 된다.!!!!

  • <div id="root"></div>와 같이 React 엘리먼트를 넣으려는 대상을 루트 DOM Node라고 한다, 이는 여러개가 될수도 있다.
  • React가 React 엘리먼트를 DOM과 일치시켜 UI최신화하는 구체적인 방법은 ReactDOM.render()함수를 이용하여 React 엘리먼트와 루트 DOM 노드를 인자로 넣는 것이다!

이미 랜더링된 엘리먼트 업데이트하기

위에서 ReactDOM.render()를 이용해서 엘리먼트와 루트 DOM 노드를 연결시켜 React가 엘리먼트를 보고 DOM을 구성하여 랜더링 시키는 것까지 했다.

이미 엘리먼트가 화면에 보이는상황
= 이미 React가 Element를 보고 DOM을 구성하여 최신 UI구성한 상황
= 이미 ReactDOM.render()함수를 통해 엘리먼트와 루트 DOM 노드를 연결한 상황

에서 엘리먼트를 업데이트 해보자.
('공식문서를 제대로 공부하기전에는 아 ㅋㅋ 리랜더링 시키려면 setState로 state 업데이트 시키면 되지 뭐 ㅋ'라는 생각을 가지고 대충 훑어 봤다..)

React 엘리먼트(객체)는 불변객체이다.
불변객체란 한번 만들어진 이후에는 절대로 직접적으로 수정이되면 안된다는 뜻이다.
수정이필요하면 아애 다른 수정한 객체를 새롭게 만들어야 한다.

그러므로 이미 만들어진 엘리먼트가 루트 DOM 노드와 연결되어 화면에 보이기 까지 했는데 업데이트를 하는 방법으론 방금 말했던 것처럼 그냥 새로운 엘리먼트(객체)를 만들어주면 되는 것이다.

그리고 공식문서 제대로 다시한 입장에서는 (state 나 props변경되면 리랜더링)같은 기계적으로 암기하던 사실을 버리고 공부할 거라서
'React에서 UI를 업데이트하는 유일한 방법은 루트 DOM Node와 리액트 엘리먼트를 ReactDOM.render()함수에 인자로 넣어서 UI를 업데이트 한다'라는 사실만 가진채 진행하겠다.

다시 진행하자면 즉,
1. React 엘리먼트는 불변객체이므로 새로운 엘리먼트를 다시 생성하고
2. ReactDOM.render()함수를 다시 호출해서 루트 DOM 노드와 방금 다시 생성한 React 엘리먼트를 인자로 넣으면 된다!

1, 2만 하면 어렵지 않게 이미 랜더링된 엘리먼트를 업데이트할수있다. (화면 업데이트 될때 마다 바뀌는 엘리먼트는 다다른 녀석들이라는걸 받아들여야한다.)

  • 그럼 해보자!
import React from "react";
import ReactDOM from "react-dom";
let count = 0;
function Greeting() {
  ++count;
  const element = <div>{`안뇽 - 인사한 횟수 : ${count}`}</div>;
  ReactDOM.render(element, document.getElementById("root"));
}
setInterval(Greeting, 1000);

공식문서와 같이 setInterval을 이용해서 1000ms마다 Greeting함수가 실행되도록 했다.

보면 Greeting함수가 호출될때마다 새로운 React element를 만들고 새로운 React element를 ReactDOM.render()에 넣는 것을 볼 수가 있다.

이 과정을 말로 풀어서 해석하면
1. Greeting함수 호출
2. count증가
3. <div>{안뇽 - 인사한 횟수 : ${count}}</div> 라는 JSX 생성 (= React.createElement() = React 엘리먼트)
4. 새롭게 만들어진 React Element객체를 ReactDOM.render()함수를 이용해 루트 DOM Node와 ReactElement를 연결
5. React(React DOM)은 React Element(객체)를 보고 DOM을 구성
6. DOM을 통해 우리에게 화면에보임
7. 1000ms 지남
8. Greeting함수 호출
9. count 증가
10. ....
....

실제로는 React.render()를 한번만 호출한다고 한다. 이는 다음장에서 대체 어떻게 된건지 알아보자

살짝 오바해서 적은것 같긴한데 나도 처음봤을땐 눈에안들어왔고 나도 다시 복습하자는 겸에서 적었다.

위 과정이 전에했던 JSX와 이번에 한 Element에 대해 모든걸 포함한다.

  • React Element는 불변객체
  • ReactDOM.render()를 통해 이미 이미 DOM구성을 끝내 최신 UI를 보여진 상태에서 다시 랜더링 하는방법으로는 React Element를 새로운 녀석으로 만들어내고 이 React Element를 루트 DOM 노드와 ReactDOM.render()함수의 인자로 넣어 React가 새로운 녀석인 Element를 보고 DOM을 구성하여 랜더링 하는 것이다.

변경된 부분만 업데이트

우리는 새로운 엘리먼트로 계속해서 DOM을 업데이트 시키는 걸 해봤다.
그런데 놀라운건 React는 ReactDOM.render()로 전달된 엘리먼트와 그 자식 엘리먼트를 이전의 엘리먼트와 비교해서 변경된 부분만 DOM을 업데이트한다는 사실이다.
VDOM!

import React from "react";
import ReactDOM from "react-dom";
let count = 0;
function Greeting() {
  ++count;
  const element = (
    <div>
      <h1>나는야 인사왕</h1>
      <p>{`안뇽 - 인사한 횟수 : ${count}`}</p>
    </div>
  );
  ReactDOM.render(element, document.getElementById("root"));
}
setInterval(Greeting, 1000);

개발자 도구창을 보면
<h1>나는야 인사왕</h1>은 변경이 되지않고
<p>안뇽 - 인사한 횟수 : ~</p>만 변경이 되는걸 볼수가 있다.

React는 이전의 엘리먼트와 새로운 엘리먼트를 비교해서 변경된 부분만 실제 DOM에 업데이트 하는 것이다.

그런데 우리는 element가 불변의 객체라 계속 새로운 element를 만들었는데 어떻게 이러지..?
라는 생각을 할수도있다.
이는 Virtual DOM때문이다.
계속해서 새로운 Element를 만들었지만 React는 변경된 부분만을 DOM에 업데이트 했다.!

  • React element는 불변객체라 새로운 객체를 만들어 `ReactDOM.rener()에 넣어서 UI 업데이트 시켰는데 React는 React element와 현재 React element를 비교해서 변경된 부분만을 실제 DOM에 업데이트 했다.

위 내용은 React 공식문서를 보고 공부한 내용입니다.
https://ko.reactjs.org/docs/rendering-elements.html

1개의 댓글

comment-user-thumbnail
2022년 9월 15일

잘 읽었습니다. 감사합니다.

답글 달기