[Vue3] - Reactivity (반응형)

목차

✅ Vue3 에서의 반응형

참고: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Vue3 에서는 데이터의 변경을 감지하고 자동으로 UI 를 업데이트 해주기 위해 Javascript 의 Proxy 개념을 도입 했습니다.

객체생성시 Proxy 객체로 만듦으로써 Vue 에서는 해당 객체의 접근 및 변경을 감지하고 변경된 내용을 UI 에 반영해줄 수 있게 됐습니다.

Proxy 객체 생성 예제

<div id="app">

</div>
<!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
<script>
var data = {
message: 10
}

function render(sth) {
var div = document.querySelector('#app');
div.innerHTML = sth;
}

var app = new Proxy(data, {
get() {
console.log('값 접근')
},
// target: 객체, property: 객체내 속성, value: 전달 받는 값
set(target, prop, value) {
console.log('값 갱신')
target[prop] = value
render(value)
}
})
</script>

Proxy 객체로 생성된 app 의 내용을 변경하게 되면 콘솔에서 “값 갱신” 이라는 로그가 뜨게 됩니다.

app.message = 'hello vue';
// 출력
'값 갱신'

✅ 객체를 반응형객체로 생성해주는 함수

Vue3 에서는 객체를 반응형 객체로 바꿔주는 함수들이 존재합니다.

reactive

객체를 반응형 객체로 변환해주는 함수입니다.

import { reactive } from 'vue';

const state = reactive({ count: 0 });

ref

import { ref } from 'vue';

const countRef = ref(0);
// 타입 스크립트일 경우 다음과 같이 타입 선업을 합니다.
const countRef = ref<number>(0);

console.log(countRef.value); // 0

computed

반응형 데이터를 기반으로 계산된 값을 정의할 수 있으며, 의존성이 변경될 때 자동으로 다시 계산됩니다.

import { reactive, computed } from 'vue';

const state = reactive({ count: 0 });
// count 값이 변경될 다시 계산해 doubleCount 값을 변경합니다.
const doubleCount = computed(() => state.count * 2);

watch

특정 반응형 데이터의 변화를 감시하고, 변화가 감지될 때마다 콜백 함수를 실행할 수 있습니다.

import { reactive, watch } from 'vue';

const state = reactive({ count: 0 });
watch(
() => state.count,
(newVal, oldVal) => {
console.log(`state.count changed from ${oldVal} to ${newVal}`);
}
);

✅ 반응형 객체의 구조분해

reactive 객체는 Proxy를 통해 내부에 있는 getter 와 setter 를 통해 반응형을 유지합니다. 하지만, 구조 분해를 통해 개별 속성을 분리하면 원본 객체에 대한 Proxy 의 연결이 끊어져, 해당 변수는 더 이상 반응형 추적을 받지 않게 됩니다.

다시 말해, Proxy 객체로 생성된 객체내의 데이터들은 Proxy 객체로 생성된게 아닌 별도의 객체로 선언된 상태이기 때문에 반응형으로 작동하지 않습니다.

구조분해할당된 객체는 toRefs 함수를 이용해 반응형 객체로 만들어줄 수 있습니다.

toRefs

toRefs 함수는 구조분해할당시 내부 데이터들을 반응형(Proxy) 객체로 만들어 반홥합니다.

import { reactive, toRefs } from 'vue';

const state = reactive({ count: 0, name: 'Vue' });
const { count, name } = toRefs(state);

// 이제 count와 name은 각각 Ref<number>와 Ref<string> 타입을 가지며, reactivity가 유지됩니다.
Share