Vue 2 vs Vue 3 - Reactivity
📦 잡동사니
하나의 키워드를 잡고 좀 편하게 정리하고 싶어 만든 잡동사니
잡동사니는 조선 후기 학자
안정복이 편찬한잡동산이(雜同散異)에서 유래된 말이다.잡동산이는
잡기(雜記)의 형태를 빌려온 책으로 구체적인 체계가 잡혀있지 않은 형식이다.항목이 다소 난잡하고 내용의 구분이 혼동되어있다고 한다. 🤣
Reactivity(반응성)
Vue는 반응성(Reactivity)이라는 개념을 가지고 있다. 이는 Vue의 핵심이라고 할 수 있는데, 이를 통해 데이터의 변화를 감지하고 자동으로 화면을 갱신할 수 있다. 이를 통해 개발자는 데이터의 변화를 직접 감지하고 화면을 갱신하는 코드를 작성할 필요가 없게 된다.
먼저 아주 간단한 예제를 통해 Vue의 반응성을 살펴보자.
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <div id="app">{{ message }}</div> <script> const { createApp } = Vue; const App = { data() { return { message: 'Hello Vue!', }; }, }; createApp(App).mount('#app'); </script>
위 코드를 실행시켜보면 vue에서 제공하는 data() 함수를 통해 message라는 데이터를 정의하고, 이를 화면에 렌더링하는 것을 확인할 수 있다. 이때 message의 값이 변경되면 화면에 렌더링된 message의 값도 자동으로 변경되는 것을 확인할 수 있다. 이는 Vue의 반응성을 통해 가능한 일이다.
그렇다면 Vue는 이와 같은 반응성을 어떻게 구현하고 있을까? Vue2와 Vue3의 반응성 구현 방식을 간단하게 비교해보자.
Vue2 - Object.defineProperty

Vue2에서는 Object.defineProperty를 사용하여 반응성을 구현한다. 이는 getter와 setter를 사용하여 객체의 속성에 접근할 때마다 getter와 setter를 호출하게 된다. 이를 통해 객체의 속성에 접근할 때마다 getter와 setter를 호출하여 객체의 변화를 감지하고 화면을 갱신할 수 있다.
<div id="app"></div> <script> const appEl = document.querySelector('#app'); function render(innerValue) { appEl.innerHTML = innerValue; } const data = { message: 'hello, vue2! hello, jayden!', }; const dataCopy = { ...data }; const handler = { get() { console.log('defineProperty getter'); return dataCopy.message; }, set(value) { console.log('defineProperty setter'); dataCopy.message = value; render(value); }, }; Object.defineProperty(data, 'message', handler); </script>
위 코드를 실행시켜보면 message의 값을 변경할 때마다 getter와 setter가 호출되는 것을 확인할 수 있다. 이를 통해 message의 값이 변경되면 화면에 렌더링된 message의 값도 자동으로 변경되는 것을 확인할 수 있다.
그런데 이 방법에는 한계가 존재한다. Object.defineProperty는 객체의 속성을 정의할 때만 동작하기 때문에 객체의 속성이 추가되거나 삭제되는 것을 감지할 수 없다. 즉, 정의해둔 message의 값이 변경되는 것은 감지할 수 있지만, message의 값이 아닌 다른 속성의 값이 변경되는 것은 감지할 수 없다는 것이다.
이 때,
dataCopy를 둔 이유는data의message속성에 접근할 때마다getter와setter가 호출되기 때문에data의message속성에 접근할 때마다data의message속성의 값이 변경되는 것을 방지하기 위함이다.정확히 vue2의 내부 구현은 아니지만, 이를 통해 vue2의 반응성이 어떻게 동작하는지 이해할 수 있다.
Vue3 - Proxy
Vue3에서는 Proxy를 사용하여 반응성을 구현한다. 이는 getter와 setter를 사용하여 객체의 속성에 접근할 때마다 getter와 setter를 호출하게 된다. 이를 통해 객체의 속성에 접근할 때마다 getter와 setter를 호출하여 객체의 변화를 감지하고 화면을 갱신할 수 있다. 또한, Proxy는 객체의 속성이 추가되거나 삭제되는 것도 감지할 수 있다.
<div id="app"></div> <script> const appEl = document.querySelector('#app'); function render(innerValue) { appEl.innerHTML = innerValue; } const data = {}; const handler = { get(target, prop) { console.log('proxy getter'); return target[prop]; }, set(target, prop, value) { console.log('proxy setter'); target[prop] = value; render(value); }, }; const proxyData = new Proxy(data, handler); </script>
정확히 vue3의 내부 구현은 아니지만, 이를 통해 vue3의 반응성이 어떻게 동작하는지 이해할 수 있다.
Proxy는Object.defineProperty와 달리data의message속성에 접근할 때마다getter와setter가 호출되지 않는다. 이는Proxy가data를 감싸고 있기 때문에data의message속성에 접근할 때마다Proxy의getter와setter가 호출되기 때문이다.또한,
Proxy의handler에서get과set은target과prop을 인자로 받는다.target은Proxy가 감싸고 있는data이고,prop은data의 속성이다. 이를 통해Proxy의handler에서target과prop을 사용하여data의 속성에 접근할 수 있다. 이 부분이Object.defineProperty와 다르게 의존성 주입을 통해data의 속성에 접근할 수 있게 했다.
📝 회고
Vue2와 Vue3의 반응성 구현 방식을 간단하게 비교해보았다. Vue2에서는 Object.defineProperty를 사용하여 반응성을 구현하고, Vue3에서는 Proxy를 사용하여 반응성을 구현한다. 이를 통해 Vue3는 Vue2보다 더욱 강력한 반응성을 제공한다는 것을 알 수 있었다. 아주 기초적인 구현이긴 하지만, Vue가 어떻게 동작하고 그 내부의 반응성이 어떻게 구현되어있는지 이해하는데 도움이 되었다.