Vue에서 동적으로 렌더링 하기

가누·2023년 1월 1일
0

이 글은 Vue2를 기준으로 작성되었습니다.

왜 필요할까?

Vue에선 보통 template을 사용하여 렌더링을 한다. 아래와 같이 template 태그 안에 HTML 태그나 컴포넌트를 넣으면 손쉽게 렌더링이 잘 되는 것을 볼 수 있다.

<template>
   <div>
      ...
   </div>
</template>

그런데 만약 경우에 따라 렌더링해야하는 컴포넌트가 다르면 어떻게 할까? 이 질문 자체가 크게 와닿지 않을 것 같아서 현재 개발 중인 노코드툴 웨이브온의 예시를 들어보도록 하겠다. 웨이브온은 피그마처럼 사용자가 원하는 도형, 버튼 등의 엘리먼트를 자유롭게 캔버스에 추가할 수 있다.

위 사진에서 각 엘리먼트는 하나의 컴포넌트라 할 수 있다. 예를 들어, 이미지 엘리먼트는 AppVideo이라는 하나의 컴포넌트, 도형은 AppButton이라는 하나의 컴포넌트로 이루어져 있다. 사용자가 어떤 엘리먼트를 추가할지, 몇 개를 추가할지는 사용자가 직접 추가하기 전까진 아무도 모른다. 따라서, 그때마다 필요한 컴포넌트를 동적으로(dynamic)하게 렌더링해야하는 것이다. 이를 위해 필요한 것이 바로 render 함수이다. 사실 render 함수는 우리도 모르게 이미 사용하고 있다. 잠시 Vue에서 컴포넌트가 마운트 되는 과정을 살펴보자.

컴포넌트 마운트 과정

우리가 template 태그 안에 작성한 HTML 코드는 Vue의 내부 로직에 의하여 render 함수로 변환된다. 그리고, render 함수는 바로 그 유명한 virtual DOM tree를 리턴한다. (virtual DOM은 말 그대로 실제가 아닌 '가상의' DOM으로 자세한 설명은 구글에 널렸다.) virtual DOM tree을 리턴한다는 것이 잘 와닿지 않을 것 같아 Vue에서 virtual DOM tree가 어떻게 구현되어 있는지 살펴보자.

// HTML
<div id="foo"></div>

// virtual DOM tree 로 변환
const vnode = {
  type: 'div',
  props: {
    id: 'foo'
  },
  children: [
    /* more vnodes */
  ]
}

위와 같이 virtual DOM tree를 구현한 것을 Vue에서는 vnode라 한다. vnode는 html 태그를 javascript의 객체로 변환한 것이다. (위 객체에 배열 내에 children을 계속해서 추가하게 된다면, virtual DOM tree를 온전하게 구현할 수 있을 것이다.) 이렇게 render 함수를 통해 생성된 virtual DOM tree는 실제 DOM에 반영되는데, 이를 '마운트' 되었다라고 한다.

본론으로

다시 본론으로 돌아와서, template을 이용하는 과정을 생략하고 render 함수를 직접 이용할 수도 있는데 바로 이를 활용하여 다이나믹하게 렌더링을 해볼 것이다.

// render 함수 예시

function render(h){
   return h('div', {class: 'Foo'})
}

render 함수는 첫 번째 파라미터로 h 함수가 자동적으로 들어온다. (h는 'hyperscript'의 약자이다.) h 함수는 위에서 살펴보았던 vnode를 리턴하는 함수로, 다음과 같이 이용할 수 있다.

const vnode = h(
  'div', // 태그 이름
  { id: 'foo', class: 'bar' }, // 각종 태그 관련 속성
  [
    h('div', {id: 'hello', class: 'bar'}) // children 
  ]
)

재미있는 점은 위와 같이 다시 h 함수를 호출하여 자식으로 추가할 수 있다는 점이다. 또한, 단순 html 태그 뿐만 아니라 컴포넌트도 h 함수를 이용하여 생성할 수 있다.

import Foo from "./Foo.vue"

function render(h){
    return h(
      Foo, // 컴포넌트 이름
      {
        props: {
          prop: 1  // prop들
        }
      },
      [
        // children
      ]
    );
}

지금까지 render 함수를 이용하여 필요할때마다 원하는 컴포넌트를 마운트 시켜보았다. 더 많은 정보를 얻고 싶으면 다음을 읽어보는 것을 추천한다.

참고한 문서:
https://vuejs.org/guide/extras/render-function.html
https://vuejs.org/guide/extras/rendering-mechanism.html

profile
가누입니다.

0개의 댓글