Virtual Dom
to Render
Kelly Woo
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?
DOM and Virtual DOM
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 처럼 트리구조를 가짐
Virtual Dom is faster than Dom, so?
Real Dom?
Virtual Dom?
Virtual Dom prevents bad performance
virtual dom도 결국 dom에 patch가 되어야 하니 DOM을 직접 제어하는 코드보다 빠를수 없다.
DOM을 필요없이 읽거나 또는 잘못된 순서로 처리 되면
bad performance를 야기시킴
redux의 창시자 Dan Abramov
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의 속성을 읽을 때도 발생
나도 다시
그려줘~
넌 관계도 없는데
왜?
Changing one DOM leads to..
Dom is Fast!
B.U.T
Reflow, Repaint aren’t
how many…;;;
VDom prevents unnecessary access to DOM
text
CSS
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
Snabbdom
vue 2.0에서 채택된 기본 virtual dom library
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�]);
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)
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'� }
snabbdom(https://github.com/snabbdom/snabbdom)
결과물
Vue create VNode Fn
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는 유일무이해야한다.
Patch function(between vnodes)
OLD VNode
NEW VNode
Vue process
update
data
watcher
create vnode
insert Queue
dom update
template
related?
duplicated
request?
any diff?
mutation
notify
Vue rendering example
그럼 다시
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
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
시킴
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]
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?
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은 자신에게 알려지지 않은 속성들에 대해서는 책임지지 않습니다.
확인을 위해 하늘색 버튼 더블 클릭
nonetheless, vue is Javascript.
결과를 아는 것 보다, 왜 그렇게 되는 것인지 이해하는 것이
vue를 더 잘 쓸 수 있는 방법
kelly.kh.woo@gmail.com
감사합니다.