Vue는 DOM 업데이트를 비동기(asynchronously)로 합니다. 데이터 변경이 발견 될 때마다 큐를 열고 같은 이벤트 루프(event loop)에서 발생하는 모든 데이터 변경을 버퍼에 담습니다.
같은 Watcher가 여러 번 발생하면 대기열에서 한 번만 푸시됩니다. 이 버퍼링된 중복의 제거는 불필요한 계산과 DOM 조작을 피하는 데 있어 중요합니다. 그 다음, 이벤트 루프 "tick"에서 Vue는 대기열을 비우고 실제 (이미 중복 제거 된) 작업을 수행합니다.
해당 포스팅에서 이벤트 루프에 대한 개념까지 다루기엔 조금 무리가 있기 때문에 추후에 따로 설명드리고, 지금은 Vue.js에서는 데이터를 통해 업데이트된 DOM에 바로 접근하기 위해선 nextTick을 활용해야 된다고 이해하시면 됩니다.
🤔 nextTick이란?
Vue.js는 일반적으로 개발자가 "데이터 중심(data-driven)" 방식으로 생각하고 DOM을 직접 만지지 않도록 권장하지만 때때로 DOM을 조작해야될 경우가 생깁니다. Vue.js가 데이터 변경 후 DOM 업데이트를 마칠 때까지 기다리려면 데이터가 변경된 직후에 Vue.nextTick (콜백)을 사용할 수 있습니다. 콜백은 DOM이 업데이트 된 후에 호출됩니다.
Vue.nextTick(() => {}) // syntax
💻 사용 예시
Vue.js에서 isApp 데이터가 true일 경우 DOM을 노출시키는 로직이 있다고 가정해봅시다. 초기값은 false로 컴포넌트 생성시점에는 isApp 값이 false이기 때문에 DOM이 생성되지 않지만, mounted 라이프사이클 시점에 isApp 데이터의 값을 true로 변경함으로써 DOM 노출 조건을 만족시켰습니다. 그리고 바로 하단에서 $refs API를 활용해서 ref 값이 target인 DOM을 접근하려고 했으나 undefined로 DOM을 찾을 수 없는 경우가 발생합니다.
<template>
<div id="app">
<div v-if="isApp">
<div ref="target">hello</div>
</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
isApp: false,
};
},
async mounted() {
this.isApp = true;
console.log(this.$refs["target"]); // 갱신안됨ㅠ
},
};
</script>
이런 문제점을 해결하기 위해 사용하는 API가 바로 nextTick입니다. 바로 nextTick을 활용해볼까요? mounted 라이프사이클 안에 this.$nextTick 구문을 추가합니다. nextTick API의 인자로 콜백함수(calllback function)를 넣어주고 여기서 DOM 참조값을 확인합니다.
<script>
export default {
...
mounted() {
this.isApp = true;
// nextTick 추가!
this.$nextTick(() => {
console.log(this.$refs["target"]); // 갱신됨!
});
},
};
</script>
nextTick 콜백함수에서 console.log를 통해 참조값을 확인하면 정상적으로 DOM 참조를 할 수 있음을 확인할 수 있습니다.
✂️ 좀 더 간결하게
$nextTick() 은 promise를 반환하므로, ES2017 async/await 문법을 사용하여 똑같은 동작을 훨씬 깔끔하게 코드를 작성할 수 있습니다.
async mounted() {
this.isApp = true;
// async/await 사용!
await this.$nextTick();
console.log(this.$refs["target"]); // 갱신됨!
},
'개발 > Vue' 카테고리의 다른 글
이 포스팅은 쿠팡파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.