1 of 27

Virtual Dom

to Render

Kelly Woo

2 of 27

Question

export default {

data () {

return {

isBlue : true

}

},

methods : {

toggleColor () {

this.isBlue = !this.isBlue

}

},

mounted () {

makeItRed( document.querySelector(‘#btn) )

}

}

.btn-red { background: red !important}

.btn-white { background: white}

.btn-blue { background: blue}

function makeItRed (el){

el.classList.add(‘btn-red’);

}

<button id = ”btn”

:class = ”isBlue? ’btn-blue’ : ’btn-white’ ”

@click = ”toggleColor

>click here</button>

When this component mounted, the background of the button is red

(makeItRed has been called and .btn-red beats .btn-blue by ‘!important’)

If you click the button, what would be the background of button?

3 of 27

DOM and Virtual DOM

4 of 27

Dom and Virtual Dom

DOM

virtual DOM

해결?

문제?

<section class=”section”>

<header class=”header”>

<h1></h1>

</header>

<article>

<div class=”box”></div>

<a href=”#”></a>

….

</article>

</section>

{

tag: ‘section’,

data: { class: ‘section’ },

children: [

{ tag: ’header’, …,

data: { class: ‘header’}

children: [ {tag: ’h1’...} ]

},

{ tag: ‘article’, … }

…..

}

document와 document 내부의 태그에 대한 정의와 api를 규격화 한 모델. 기존 BOM(Browser object model)의 크로스 브라우징이 어려워 w3c에서 권고됨.

DOM을 본따 만든 javascript object.

메모리상에 있어 생성과 수정, 삭제가 빠름. Dom 처럼 트리구조를 가짐

5 of 27

Virtual Dom is faster than Dom, so?

Real Dom?

Virtual Dom?

6 of 27

Virtual Dom prevents bad performance

virtual dom도 결국 dom에 patch가 되어야 하니 DOM을 직접 제어하는 코드보다 빠를수 없다.

DOM을 필요없이 읽거나 또는 잘못된 순서로 처리 되면

bad performance를 야기시킴

redux의 창시자 Dan Abramov

7 of 27

Virtual Dom prevents bad performance

chrome > 개발자 도구 >console drawer> rendering > paint flashing 체크

Green => reflow, repaint

DOM의 업데이트 내용을 다시 브라우저에 표시하기 위해 다시 layout을 계산하고 그리는 작업(reflow, repaint)이 발생, 변경된 DOM뿐 아니라 근처의 DOM과 node tree의 DOM 까지 영향을 주기 때문에 필요하지 않은 과정이 반복된다면

performance에 악영향을 줌

이런 layout 재작업은 DOM의 속성을 읽을 때도 발생

나도 다시

그려줘~

넌 관계도 없는데

왜?

8 of 27

Changing one DOM leads to..

Dom is Fast!

B.U.T

Reflow, Repaint aren’t

how many…;;;

9 of 27

VDom prevents unnecessary access to DOM

text

CSS

10 of 27

Other Benefits

$('.img').mouseover(function(e){

if (err ) {

$('.tranvel-msg').text(err)

.show();

}

}).mouseout(function(e){

$('.tranvel-msg').hide();

})

<img src="img.png" class="img"

@mouseover="show = error && true"

@mouseout="show = false">

<div class='travel-msg'

v-show="show">{{{error}}}</div>

jQuery

Vue

  1. DOM과 유사한 형태로 쓰기 때문에 가독성 증가
  2. 쉬운 유지 보수 확장
  3. DOM의 정적인 attrs 를 functional 하게 만들어줌

11 of 27

Snabbdom

vue 2.0에서 채택된 기본 virtual dom library

12 of 27

snabbdom(https://github.com/snabbdom/snabbdom)

const snabbdom = require('snabbdom/snabbdom.js');

import h from 'snabbdom/h'; //create new virtual dom

const patch = snabbdom.init([� require('snabbdom/modules/class').default,� require('snabbdom/modules/props').default,� require('snabbdom/modules/style').default,� require('snabbdom/modules/eventlisteners').default]);

13 of 27

snabbdom(https://github.com/snabbdom/snabbdom)

let oldv = document.getElementById('static_dom');let vnode = h('div#static_dom', {class: [ 'classed'],� style: { color: '#f00', textDecoration: ‘underline’ },� on: { click: changeToButton }}, 'but changed by virtual dom');

setTimeout(function () { oldv = patch(oldv, vnode); }, 3000)

14 of 27

snabbdom(https://github.com/snabbdom/snabbdom)

let oldv = document.getElementById(‘dom’)

function createVNode () {return h(this.tag, this.data, this.children)}

function updateObj (oldv, data) {

return patch(oldv, createVNode.call(data)

}

oldv = updateObj(obj)

// obj 내부의 데이터에 setter로 updateObj를 호출하거나 pubsub 패턴을 더한다면 data에 따라 값이 바뀌는 원시 Vue 완성

var obj = {� tag: 'button',� data: {� type: 'button',class: { 'btn': true, 'btn-green': true },� on: {� click: function () {�window.open('https://kr.vuejs.org/v2/guide/render-function.html','_blank');}}},� children: 'To Vue Blog'}

15 of 27

snabbdom(https://github.com/snabbdom/snabbdom)

결과물

16 of 27

Vue create VNode Fn

17 of 27

Vue render function

render: function (h) {

var vm = this // this는 현재의 component를 가리킴

var myHi = h('p', 'hi')

return h( 'div' , … //tag

{ … //data object class, staticClass, style, }⁰,

[myHi, Object.assign({}, myHi)¹]) //children

}

//0. https://kr.vuejs.org/v2/guide/render-function.htm 실제 data structure

//1. vnode는 유일무이해야한다.

18 of 27

Patch function(between vnodes)

OLD VNode

NEW VNode

19 of 27

Vue process

update

data

watcher

create vnode

insert Queue

dom update

template

related?

duplicated

request?

any diff?

mutation

notify

20 of 27

Vue rendering example

그럼 다시

21 of 27

Rendering example(https://kellywoo.github.io/vnode/ -2.render)

숫자가 렌더링 템플릿에 더해짐

숫자가 렌더링 템플릿에 없음

show Numbers: true

show Numbers : false

아무리 버튼을 클릭해도 숫자 증가 없음

각 숫자는 해당 컴포넌트가 새로운 virtual dom을 생성할때 마다(render function 호출 때 마다) 1씩 증가

버튼 클릭시 child component만 1씩 증가,

자식 컴포넌트인 grand-child 는 변경없음

click

click4

22 of 27

keep-alive example(https://kellywoo.github.io/vnode/ -3.vnode)

seranio

vnode의 keep-alive 제어

child comp의 v-if 제어

classLIst.add로 dom에

.btn-red 를 더함

.btn-red{

background:red !important}

현재는 .btn-blue {background:skyblue}

A

B

C

c를 눌러 버튼을 변경

버튼에 빨간색이 적용

B를 2번 눌러

child component를

remove => create

시킴

23 of 27

keep-alive example(https://kellywoo.github.io/vnode/ -3.vnode)

case: false

버튼에 빨간색이 적용이 사라짐

버튼에 빨간색이 적용이

그대로임

case: true

console에 vueconsole()을 입력, parent component.$children 항목을 볼 수 있습니다.

-keep-alive: false

child destroy hook이 발생되며

component가 제거되어 create을 누르면 다시 component가 생성, element도 재생성되며 기존에 있던 .btn-red 클래스는 사라짐.

vueconsole() => (2) [a, a]

-keep-alive: true

child deactivate hook이 발생,

자식 컴포넌트가 그대로 남아있어,create을 눌렀을 때 별도의 data 변경이 없다면

render 함수가 실행되지 않아 이전의 $el을

그대로 보여줌

vueconsole() => (3) [a, a, a]

24 of 27

Answer : white

export default {

data () {

return {

isBlue : true

}

},

methods : {

toggleColor () {

this.isBlue = !this.isBlue

}

},

mounted () {

makeItRed( document.querySelector(‘#btn) )

}

}

.btn-red { background: red !important}

.btn-white { background: white}

.btn-blue { background: blue}

function makeItRed (el){

el.classList.add(‘btn-red’);

}

<button id = ”btn”

:class = ”isBlue? ’btn-blue’ : ’btn-white’ ”

@click = ”toggleColor

>click here</button>

When this component mounted, the background of the button is red

(makeItRed has been called and .btn-red beats .btn-blue by ‘!important’)

If you click the button, what would be the background of button?

25 of 27

Again, Patch function doesn’t care the element’s state

OLD VNode

NEW VNode

patch 함수 내부에선 old vnode와 new vnode 만 비교,

class 영역의 diff 발견 => element의 class 업데이트

이때 vnode와 연결되지 않은 .btn-red 클래스는 사라집니다.

Virtual Dom은 자신에게 알려지지 않은 속성들에 대해서는 책임지지 않습니다.

확인을 위해 하늘색 버튼 더블 클릭

26 of 27

nonetheless, vue is Javascript.

결과를 아는 것 보다, 왜 그렇게 되는 것인지 이해하는 것이

vue를 더 잘 쓸 수 있는 방법

27 of 27

kelly.kh.woo@gmail.com

감사합니다.