[들어가기 전에]
Vue를 접하면서 점차 주어진 기능만 구현하려고 하는... 그러니까 돌아가기만 하면 된다는 마인드를 가진 이른바 'Coder'가 되어가는 걸 느꼈는데요..!
이를 지양하고자.. Vue에 대한 원리를 이해하고 기능적인 측면뿐만 아니라 성능적인 측면도 고려하는 게 좋을 거 같아 본 글을 작성하게 되었습니다 🙄
[브라우저에서의 렌더링 동작 과정]
가상 DOM을 알기 전에, 브라우저에서 렌더링이 어떻게 동작하는지 알아보겠습니다.
렌더링은 통신을 통해 요청한 HTML, CSS, JavScript를 받아서 화면에 뿌려주는 역할을 합니다.
화면에 Display하기 위해서는 DOM Tree와 Render Tree 이렇게 2가지 Tree를 필요로 하는데요,, Tree를 중점으로 렌더링 동작 과정을 기억하시면 이해가 빠를 거예요!
동작 과정은,
- HTML 문서를 파싱하여 DOM Tree를 만들어냅니다. 이와 동시에 CSS를 파싱하여 Style Rules을 만들어냅니다.
- 1번에서 만든 DOM 노드와 시각 정보를 연결하여 Render Tree를 만들어냅니다.
- Render Tree 생성이 끝나면 Layout이 시작하는데 이는 각 노드가 화면의 정확한 위치에 표시되는 것을 의미합니다.
- 그 후, Painting함으로써 화면에 Display를 하여 렌더링 과정이 끝납니다. 중요한 점은, 렌더링 엔진은 최선의 사용자 경험을 끌어내기 위해 모든 HTML 문서를 파싱하는 데에 기다리지 않고 Layout과 Painting을 합니다. 그러니까 네트워크로부터 모든 내용을 받기 이전에 받은 내용의 일부를 먼저 화면에 표시하게 됩니다.
이러합니다!
브라우저 동작 과정을 자세히 알고 싶다면 아래 링크를 참고하시면 됩니다. 엄청 꼼꼼합니다 :)
https://d2.naver.com/helloworld/59361
그런데,, 가상 DOM을 알기 전에 렌더링 동작 과정을 왜 알아야 할까요?
바로 DOM(Document Object Model)이 업데이트할 때마다 성능적으로 엄청난 비용이 든다는 단점이 있기 때문이죠!
이 단점을 해결해주는게 가상 DOM입니다.
[가상 DOM]
가상 DOM은 비효율적인 연산 즉, 화면에서 업데이트가 발생할 때마다 Render Tree도 계속해서 업데이트된다는 비효율을 줄이기 위해 등장하였습니다.
변화가 일어나면 Virtual DOM을 생성하고 만들어진 Virtual DOM끼리 비교하여 차이점을 파악합니다. 그럼 해당 차이점만 실제 DOM에 적용하면 되는 것이죠.
그럼 당연히 통째로 업데이트하지 않고 일부분(=차이점)만 업데이트하면 되니까 향상된 성능을 가질 수 있겠죠?!
[nextTick]
음... 뜬금없이 nextTick()이 왜 나왔을까요? 저도 이 내용을 따로 올리고 싶었지만 렌더링 동작 과정을 설명하였으니 관련 있는 내용이라 여기서 설명하겠습니다!
먼저 우리는 브라우저에서의 렌더링 동작 과정 중 4번째 단계에 집중해야 합니다.
렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시하는데 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다. 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시하는 것이다.
그렇기 때문에 네트워크 요청을 하거나 Data가 업데이트가 되자마자 업데이트될 UI에 대해서 Vue가 DOM을 찾지 못하는 경우가 발생합니다. 즉, 반응형 상태를 업데이트한 결과는 동기적으로 DOM에 업데이트되지 않습니다..
이 문제를 해결하기 위해서 나온 게 nextTick()입니다!
Vue에서 비동기적인 DOM 업데이트 후에 콜백 함수를 실행할 수 있도록 도와주는 함수입니다.
<script>
import { ref, nextTick } from 'vue'
export default {
setup() {
const message = ref('초기 메시지');
const updateMessage = () => {
message.value = '새로운 메시지';
nextTick(() => {
// UI 업데이트 후에 실행
console.log('메시지가 업데이트되었습니다.');
});
};
return {
message,
updateMessage,
}
}
}
</script>
<template>
<h1>{{ message }}</h1>
<button @click="updateMessage()">메시지 업데이트</button>
</template>
유용한 경우는 3가지 상황이 있는데요,
- 데이터 변경 후에 DOM 업데이트가 완료된 상태에서 추가 작업을 수행해야 할 때
- Vue 컴포넌트에서 ref를 사용하여 DOM 요소에 직접 접근하고 업데이트된 DOM을 조작해야 할 때
- Vue 라이프사이클 훅에서 비동기 작업을 수행하고, 작업이 완료된 후에 다음 단계로 진행해야 할 때
이러한 경우에 사용하시면 될 거 같습니다!
결론적으로...! nextTick() 함수를 사용하면 Vue가 내부적으로 DOM 업데이트를 처리하고 나서 콜백 함수를 실행하므로 안정적으로 DOM 조작을 수행할 수 있음을 기억하면 됩니다 😎
'Vue.js' 카테고리의 다른 글
[Vue.js] v-slot으로 컴포넌트 효율적으로 사용하기 (0) | 2023.09.25 |
---|---|
[Vue.js] axios 라이브러리를 사용한 API 호출 (0) | 2023.09.23 |
[Vue.js] 부모 컴포넌트 ↔ 자식 컴포넌트 데이터 전달 (0) | 2023.09.22 |
[Vue.js] computed와 watch 그리고 watchEffect (0) | 2023.09.12 |
[Vue.js] 반응형 ref와 reactive 알아보기 (0) | 2023.09.07 |