[React] 리액트야, 요소를 렌더링해라!

MOON HEE·2022년 6월 10일
0
post-thumbnail

💡 핵심 : 컴포넌트 렌더링을 위해 모든 컴포넌트는 createElement 함수를 통해 element로 변환된다.

1. Elements(요소, 성분)


Element는 리액트 앱을 구성하는 가장 작은 블록들을 의미한다.

Element는 원래 웹사이트에 대한 모든 정보를 담고 있는 객체인 DOM에서 사용하는 용어라, Element라고 하면 DOM Element를 의미했다. 여기서의 Element는 DOM Elements이다.(개발자도구의 '요소' 개념)

리액트 초창기, '화면에 나타나는 내용을 기술하는 자바스크립트 객체'가 필요했고 처음에는 Descriptor라는 이름으로 불렸지만 DOM과의 통일성을 위해 Element라고 불리게 됐다. 따라서 리액트 Element는 DOM Element의 가상표현이라고 할 수 있다.

리액트 Elements는 화면에 보이는 것들을 기술한다.

const element = <h1>Hello, world</h1>;

위 코드의 오른쪽 부분은 리액트의 createElement 함수를 사용하여 Element를 생성하게 된다. 이렇게 해서 생성되는 것이 리액트 Element다. 또 리액트 Element는 DOM Element를 생성하게 된다.


2. Elements의 형태


리액트 Elements는 자바스크립트 객체 형태로 존재한다. 이 객체는 불변성을 가지고 있다. 즉, 한번 생성되면 바꿀 수 없다.

{
	type: 'button',
    props: {
    	className: 'bg-green',
        children: {
        	type: 'b',
            props: {
            	children: 'Hello, element!'
            }
        }
    }
}

위 코드는 버튼을 만들기 위해 작성한 jsx 문법이다. type에는 html태그가 들어가고 props에는 속성이 들어간다. 이 Elements가 실제로 렌더링된다면 아래 코드처럼 된다.
참고 : React.createElement(component, props, ...children)


<button  class='bg-green'>
	<b>
    	Hello, element!
    </b>  
</button>

그렇다면 Element type의 html 태그 이름이 문자열로 들어간게 아닌 경우에는 어떻게 해야 할까?


{
	type: Button,
    props: {
		color: 'green',
          children: 'Hello, element!'
    }
}

위 코드는 리액트의 컴포넌트 element를 나타낸다. type에 리액트 컴포넌트의 element가 들어갔다. 이 객체는 createElement함수가 만들어준다.


function Button(props) {
	return (
		<button className={`bg-${props.color}`}>
        	<b>
              {props.children}
        	</b>
        </button>
	)
}

function ConfirmDialog(props) {
	return (
    	<div>
        	<p>내용을 확인하셨으면 확인 버튼을 눌러주세요.</p>
        	<Button color='green'>확인</Button>
        </div>
    )
}

위 코드에는 ConfirmDialog 컴포넌트에 Button 컴포넌트가 포함되어 있다. ConfirmDialog 컴포넌트가 렌더링 되면 어떤 형태일까?


{
	type: 'div',
    props: {
  		chilren: [
  			{
                type: 'p',
                props: {
                    children: '내용을 확인하셨으면 확인 버튼을 눌러주세요.'
                }
  			},
  			{
  				type: Button,
  				props: {
  					color: 'green',
  					children: '확인'
  				}
  			}
  		]
  	}
}

div의 첫번째 children은 type이 html 태그이므로 곧바로 렌더링이 된다.
반면 두번째 children의 type은 Button이라는 리액트 컴포넌트이다. 이 경우 리액트는 Button 컴포넌트에 element를 생성해서 합치게 된다. 그래서 최종적으로 element는 다음과 같은 모습이 된다.

{
	type: 'div',
    props: {
  		chilren: [
  			{
                type: 'p',
                props: {
                    children: '내용을 확인하셨으면 확인 버튼을 눌러주세요.'
                }
  			},
  			{
  				type: {
                	type: 'button',
                  	props: {
                    	className: 'bg-green',
                      	children: {
                        	type: 'b',
                          	props: {
                            	children: '확인'
                            }
                        }
                    
                }
  			}
  		]
  	}
}

3. Elements의 특징


리액트 Element는 <불변성>을 갖는다!(매우 중요)

Elements 생성 후에는 children이나 attributes를 바꿀 수 없다.
Elements는 다양한 모습으로 존재할 수 있지만 한번 생성된 다음에는 변경이 불가능하다는 의미이다.
리액트는 빠른 렌더링이 특징이다. 이를 위해 Virtual DOM을 사용한다.

위 그림은 Virtual DOM의 개념도다. 각 동그라미는 Element를 의미한다. 이 그림에서처럼 화면에 새로운 내용을 보여주기 위해서 Virtual DOM은 변경된 부분을 계산(Compute Diff)하고 해당 부분만을 다시 렌더링(Re-render)한다.

빨간색 표시된 부분이 변경된 Elements다. Elements는 불변성을 갖고있기 때문에 화면에 새로운 내용을 보여주기 위해서는 새로운 Element를 생성해 기존 Element가 연결되어 있는 부분에 바꿔서 단다.

이러한 이유로 상태관리와 더불어 화면이 얼마나 자주 갱신되는지는 성능에 큰 영향을 미친다.


4. Elements 렌더링하기


Root DOM Node

<div id="root"></div>

이 코드는 모든 리액트에는 필수적으로 들어가는 아주 중요한 코드이다. 이 아래에 리액트 Elements가 렌더링되며 리액트에 의해 관리되기 때문에 Root DOM Node라고 부른다. 여러 개 일 수도 있다.

const element = <h1>안녕, 리액트!</h1>;
ReactDOM.render(element, document.getElementById('root'));

Root div에 렌더링하기 위해서는 위와 같은 코드를 쓴다. 이 코드는 element를 하나 생성하고 생성된 element를 Root div에 렌더링한다는 내용이다.

렌더링하기 위해 ReactDOM에 render()라는 함수를 사용하게 된다. 이 함수는 첫번째 파라미터의 리액트 Element를, 두번째 파라미터인 html element(즉 DOM element)에 렌더링하는 역할을 한다.

이를 통해 리액트 element는 리액트 Virtual DOM에 존재하는 것이고 DOM element는 실제 브라우저의 DOM에 존재하는 것을 다시 확인할 수 있다.


5. 렌더링된 Elements를 업데이트하기


Elements는 한번 생성되면 바꿀 수 없기 때문에 업데이트하기 위해서는 다시 생성해야 한다.

function tick() {
	const element = (
    	<div>
      		<h1>안녕, 리액트!</h1>
        	<h2>현재 시간: {new Date().toLocaleTimeString()}</h2>
      	</div>
    );
  
  ReactDOM.render(element, document.getElementById('root'));
}

setIntercal(tick, 1000)

tick함수는 element를 생성하여 이를 Root div에 렌더링하는 역할을 한다. 그리고 setIntercal()를 사용하여 1000ms마다 tick 컴포넌트를 호출하고 있다.

실행시켜서 요소창을 살펴보면 매초마다 생성되어 시간 부분이 깜빡이는 것을 확인할 수 있을 거다.

이를 통해 Elements는 업데이트하기 위해서 다시 생성해야 한다는 것을 다시 한번 알 수 있다.

profile
자고 일어나면 해결되는게 더 많은 듯 그럼 잘까

0개의 댓글