[React] Element의 불변성과 렌더링/리렌더링

parkheeddong·2023년 5월 9일

React

목록 보기
3/13
post-thumbnail

1. Elemenet란?!

리액트 앱을 구성하는 '가장 작은 블록'이다!

📌 React Element vs Dom Element

Dom Element는 HTML 요소를 의미한다.
Dom Element = 실제 브라우저 DOM에 존재하는 Element
React Element = 가상 DOM에 존재하는 Element

📌 React Element 생성하기

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

-> 이 JSX코드는 내부적으로 createElement 함수를 호출하는 javascript 코드로 변환된다. 따라서 createElement 함수로 가상 돔에 존재하는 React의 element가 생성된다. 이를 통해 이후 React는 실제로 Dom의 element를 만들게 된다 ❗

📌 React Element는 자바스크립트 객체의 형태로 존재한다.

🔔 실제 React Element의 모습

아래 코드는 실제 버튼을 나타내는 React Element의 모습이다. 즉, 실제로는 자바스크립트 객체이다.

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

🔔 DOM Element의 모습

위 React Element가 실제로 렌더링된다면, 다음과 같은 Dom Element가 된다.

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

🔔 element type에 실제 HTML 타입이 아닌 이름이 문자열로 들어간다면?!

이 자바스크립트 객체는 type에 문자열 html 태그 'button'이 아닌, Button이라는 react component의 이름이 들어갔다는 점이다.

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

이 코드에서는 Button 컴포넌트와 ComfirmDilaog 컴포넌트가 있다. ComfirmDilaog의 element는 어떤 모습일까?

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 element는 다음과 같을 것이다!

{
	type : 'div',
    props : {
    	children : [
        {
        	type : 'p',
            props : {
            	children : '내용 확인 시 버튼 누르기'
            }
         },
         {
         	type : Button,
            props : {
            	color : 'green',
                children : '확인'
            }
         }
        ]
     }
 }

이 때, div의 children 중 'p'태그는 바로 렌더링이 가능한 상태다. 그러나 Button은 html 태그가 아닌 리액트 컴포넌트의 이름이다. 따라서 리액트는 Button 컴포넌트의 element를 생성해서 합치게 된다.

{
	type : 'div',
    props : {
    	children : [
        {
        	type : 'p',
            props : {
            	children : '내용 확인 시 버튼 누르기'
            }
         },
         {
         	type : 'button',
            props : {
            	className : 'bg-green',
                children : {
                	type : 'b',
                    props : {
                    	children : '확인'
                    }
                 }
            }
         }
        ]
     }
 }

이렇게, 컴포넌트 렌더링을 위해 모든 컴포넌트가 createElement를 통해 element로 변환된다는 것을 기억하자 !

2. React Element의 불변성(Immutable)

React Element는 절대! 변하지 않는다.

React Element가 생성된 이후에는, children이나 attribute를 바꿀 수 없다.

가상 돔은 화면에 새로운 내용을 보여주기 위해서, 가상 돔의 변경된 부분(State Change)을 계산(Compute Diff)하고 해당 부분을 다시 렌더링(Re-rendering) 한다.

변경된 부분을 반영하기 위해서는, element는 불변성을 가지고 있기 때문에 해당 element를 제거하고 새로운 element를 만들어 대체하면 된다.

🔔 Elements 렌더링 하기

<div id = 'root'> </div>

이 코드는 모든 리액트 앱에 들어가는 코드로서,
이 div 태그는 root DOM node이다.
리액트로 만들어진 모든 웹사이트는 하나의 root DOM node를 가진다.

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

루트 Div에 실제 리액트 element를 렌더링하기 위해선 다음과 같이 element를 생성하고, 생성된 element를 root div에 랜더링한다.
랜더링을 할 때에는 'ReactDom'의 render() 함수를 이용한다.
render 함수는 첫번째 파라미터인 ✔ "React element"(Virtual DOM)✔를 두번째 파라미터인 ✔html "DOM element"(실제 브라우저의 DOM)✔에 렌더링한다.

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

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

tick함수가 호출될 때마다 element가 변경되는 것이 아니라, 새로운 element가 생성되고 대체되는 것이다.

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

setInterval(tick, 1000);

0개의 댓글