엘리먼트 렌더링
엘리먼트
Element라는 영단어는 요소, 성분이라는 뜻을 갖고 있습니다. 어떤 물체를 구성하는 성분을 영어로 엘리먼트라고 합니다. 마찬가지로 리액트 앱을 구성하는 요소를 의미합니다.
Elements are the smallest building blocks of React apps
“엘리먼트는 리액트 앱의 가장 작은 빌딩 블록들”
웹 개발에서의 엘리먼트는 원래 웹사이트에 대한 모든 정보를 담고 있는 객체인 DOM(Document Object Model)에서 사용하는 용어입니다. 그래서 기존에는 엘리먼트라고 하면 DOM 엘리먼트를 의미했습니다.

위 그림에서 보이는 것처럼 탭 이름부터 ‘Elements’로 되어 있기 때문에 엘리먼트를 모아놓았다는 것임을 알 수 있습니다. 하지만 다른점은 이곳에서 보이는 엘리먼트는 리액트 엘리먼트가 아닌 DOM 엘리먼트이며 HTML 요소를 나타냅니다.
리액트 엘리먼트와 DOM 엘리먼트의 차이가 뭘까요?..
리액트가 개발되기 시작한 초창기에는 화면에 나타내는 내용을 기술한 자바스크립트 객체를 일컫는 용어가 필요했습니다. 처음에는 describe (기술하다)에서 파생된 descriptor라는 이름으로 불렸었는데 최정적으로 나타내는 형태는 DOM 엘리먼트 였기 때문에 DOM과의 통일성을 위해서 엘리먼트라고 불렀습니다.

실제 브라우저에서 DOM에 존재하는 엘리먼트는 DOM 엘리먼트가 되는 것이고, 리액트의 Virtual DOM에 존재하는 엘리먼트가 바로 리액트 엘리먼트가 되는 것입니다. 결국 리액트 엘리먼트는 DOM 엘리먼트의 가상표현이라고 볼 수 있습니다.
위 코드처럼 리액트 엘리먼트는 화면에서 보이는 것을 기술합니다. 대입 연산자 (’=’) 왼쪽 부분에 나오는 변수 이름이 element로 되어 있는 것을 볼 수 있습니다.
이 코드가 실행이 될 때, 대입 연산자의 오른쪽 부분은 createElement( ) 함수를 사용하여 엘리먼트를 생성하게 됩니다. 이렇게 생성된 것이 바로 리액트 엘리먼트가 되는 것입니다. 리액트는 이 엘리먼트를 이용해서 실제 화면에서 보게될 DOM 엘리먼트를 생성합니다.
엘리먼트의 생김새
리액트 엘리먼트는 어떻게 생겼을까요?
리액트 엘리먼트는 자바스크립트의 객체 형태로 존재합니다. 엘리먼트는 컴포넌트 유형과 속성 및 내부의 모든 자식에 대한 정보를 포함하고 있는 일반적인 자바스크립트 객체입니다. 이 객체는 마음대로 변경할 수 없는 불변성(immutable)을 갖고 있습니다. 한 번 생성되면 바꿀 수 없다는 뜻이죠
위 코드는 버튼을 나타내기 위한 엘리먼트입니다. 자바스크립트 객체임을 알 수 있습니다. 위 코드처럼 type에 HTML 태그 이름이 문자열로 들어가는 경우, 엘리먼트는 해당 태그 이름을 가진 DOM Node를 나타내고 props는 속성을 나타냅니다. 해당코드는 아래와 같은 DOM 엘리먼트가 될 것입니다.
엘리먼트의 type에 HTML 태그 이름이 문자열로 들어가는 것이 아닌 경우에는 어떻게 될까요?
위 코드는 리액트의 컴포넌트 엘리먼트를 나타낸 것입니다. 이역시도 일반적인 자바스크립트 객체입니다. 다만, 위에 나왔던 엘리먼트와 한 가지 다른 점은 type에 HTML 태그가 아닌 리액트 컴포넌트의 이름이 들어갔습니다.
이처럼 리액트 엘리먼트는 자바스크립트 객체 형태로 존재합니다. 그리고 이 객체를 만드는 역할을 하는 것이 바로 createElement ( ) 함수입니다.
createElement ( ) 의 인수를 살펴보기
첫 번째 파라미터로는 타입이 들어갑니다. HTML 태그 이름이 문자열로 들어가거나 또 다른 리액트 컴포넌트가 들어가게 됩니다. 이것이 개발자 도구를 통해서 보았던 HTML 태그가 되는 것이죠
만약 HTML 태그가 아닌 리액트 컴포넌트를 넣으면 어떻게 될까요?
모든 리액트 컴포넌트는 최종적으로 HTML 태그를 사용하게 되어있습니다. 하나의 컴포넌트는 여러 개의 자식 컴포넌트를 포함할 수 있고, 자식 컴포넌트를 모두 쭉 분해해 보면 결국 HTML 태그가 나오는 것이죠
두 번째 파라미터로는 props라는 것이 들어갑니다. 이는 간단히 말하자면 style과 같은 엘리먼트의 속성입니다. 이런 속성을 attrubutes라고 부릅니다.
세 번째 파라미터로는 children이 들어가게 됩니다. 해당 엘리먼트의 자식 엘리먼트들이 이 부분에 들어가게됩니다. 실제 개발자 도구의 그림에서는 HTML 태그 하위에 다시 여러 개의 HTML 태그가 나오는 것을 볼 수 있습니다. 이러한 HTML 태그들이 결국 자식 엘리먼트가 되는 것입니다.
createElement( ) 함수의 동작과정을 살펴보겠습니다.
위 코드에는 Button 컴포넌트와 ConfirmDialog 컴포넌트가 있으며. ConfirmDialog 컴포넌트가 Button 컴포넌트를 포함하고 있습니다. 여기에서 ConfirmDialog 컴포넌트의 엘리먼트는 어떤 모습이 될까요
첫 번째 children은 type이 HTML인 p태그 이기 때문에 곧바로 렌더링이 될 수 있는 상태입니다. 하지만 두 번째 type의 이름은 리액트 컴포넌트의 이름인 Button입니다. 이 경우에 리액트는 Button 컴포넌트의 엘리먼트를 생성해서 합치게 됩니다. 최종적으로 엘리먼트는 아래와 같은 모습이 될 것입니다.
이처럼 컴포넌트의 렌더링을 위해서는 모든 컴포넌트가 createElement( ) 함수를 통해 엘리먼트로 변환된다는 것을 알아보았습니다.
엘리먼트의 특징
엘리먼트는 중요한 특징 불변성을 가지고 있습니다. 이는 말 그대로 변하지 않는 성질을 의미합니다. 즉, 엘리먼트가 불변성을 갖고 있다는 것은 한 번 생성된 엘리먼트는 변하지 않습니다. 따라서 생성 후에는 children이나 attributes를 바꿀 수 없습니다.
변하지 않는다고 했는데 화면 갱신이 안되는거 아닌가요?… SPA인데..
이 의문을 해소하려면 불변성에 관한 설명을 자세히 읽어보아야 합니다. 엘리먼트는 생성 후에는 children이나 attributes를 바꿀 수 없습니다. 놓친 부분이 있습니다. 바로 엘리먼트 생성 후라는 부분입니다. 즉, 엘리먼트는 다양한 모습으로 존재할 수 있지만 한 번 생성된 다음에는 변경이 불가능하다는 뜻입니다.
붕어빵 가게에 가면 붕어빵 틀에 반죽을 넣고 시간이 지나 그 안에서 붕어빵이 구워져 나오는 것을 볼 수 있는데, 구워져 나온 붕어빵의 속 내용은 바꿀수 없는 것과 같은 이치라고 생각하면 됩니다.

위 그림에는 리액트의 컴포넌트와 엘리먼트의 관계가 나타나 있습니다. 붕어빵이 컴포넌트라는 틀에 구워져서 밖으로 나오는 과정을 엘리먼트를 생성하는 것이라고 말할 수 있습니다. 그리고 생성이 끝난 것이기 떄문에 변경할 수 없는 것이죠.
화면에 변경된 엘리먼트들을 보여주기 위해서는 어떻게 해야하나요?..
기존 엘리먼트를 변경하는 것이 아닙니다. 새로운 엘리먼트를 만들면 됩니다. 이후 기존에 엘리먼트와 새로운 엘리먼트를 바꿔치기 하는 것입니다. 리액트의 장점 중 하나로 빠른 렌더링 속도를 언급하였습니다.

위 그림과 같이 화면에 새로운 내용을 보여주기 위해서 가상돔 (Virtual DOM)은 변경된 부분을 계산(Compute Diff)하고 해당 부분만 다시 렌더링 합니다. 여기에서 각 동그란 각 원들이 바로 엘리먼트입니다. 그리고 빨간색으로 표시된 원들은 변경된 엘리먼트가 되는 것이죠. 엘리먼트는 이전에 말했듯이 불변성을 갖고 있기 때문에 새로운 내용을 보여주기 위해서는 새로운 엘리먼트를 만들어 기존 엘리먼트가 연결되어 있는 부분에 바꿔달면 됩니다.
엘리먼트의 불변성은 가장 큰 특징입니다. 상태 관리와 더불어 화면이 갱신되는 횟수 (얼마나 화면이 자주 바뀌는지)는 실제 리액트를 이용한 개발과정에서 성능에 큰 영향을 미치는 요소입니다.
엘리먼트 렌더링 하기
엘리먼트를 생성한 이후 화면에 보여주기 위해서는 렌더링이라는 과정을 거쳐야 합니다.
이 HTML 코드는 root라는 id를 가진 <div>
태그입니다. 이 <div>
태그 안에 리엑트 엘리먼트들이 렌더링되며, 이것을 Root DOM node라고 부릅니다. 오직 리액트만으로 만들어진 모든 웹사이트들은 단 하나의 Root Dom node를 가지게 됩니다. 반면에 추가적으로 리액트를 연동하게되면 여러 개의 분리된 수많은 Root DOM node를 가질 수도 있습니다.
위에서 썻던 root <div>
에 리엑트 엘리먼트를 렌더링 하기 위해서는 아래와 같은 코드를 사용하여야 합니다.
이 코드는 먼저 엘리먼트를 하나 생성하고 root div에 렌더링 하는 코드입니다. 렌더링을 하기 위해서 ReactDOM의 render( )라는 함수를 사용하게 됩니다. 이 함수는 첫 번째 파라미터인 element를 두 번째 파라미터인 HTML 엘리먼트에 렌더링하는 역할을 합니다. 리액트의 엘리먼트는 리액트의 Virtual DOM에 존재하는 것이고, HTML 엘리먼트는 실제 브라우저의 DOM에 존재하는 것입니다. 결국 리액트의 엘리먼트가 렌더링되는 과정은 Virtual DOM에서 실제 DOM으로 이동하는 과정이라고 할 수 있습니다.
렌더링 엘리먼트 업데이트하기
앞에서 보았듯 업데이트를 하기 위해선 이전 코드를 수정할 수 없고, 즉 다시 생성을 해야합니다.
위 코드에서는 tick( ) 이라는 함수를 정의하고 있습니다 tick ( ) 함수는 현재 시간을 포함하고 있는 엘리먼트를 생성하여 root div에 렌더링 하는 역할을 합니다. 그리고 자바스크립트의 setInterval( ) 함수를 사용해서 tick( ) 함수를 매초 호출하고 있습니다. 결과는 매초 화면에 새로운 시간이 나오게 될 것입니다. 이는 내부적으로 tick ( ) 함수가 호출될 때마다 기존 엘리먼트를 변경하는 것이 아니라 새로운 엘리먼트를 생성해 바꿔치기 하는 것 입니다.