반응형이란, 데이터가 변경되었을 때 이를 감지하고 이에 반응하여 DOM이 자동으로 업데이트 되는 성질을 말한다. 즉, 데이터를 변경하면 화면이 변경되는 것이다.
쉬운 이해를 위해 반응형 상태를 생성하는 코드를 살펴보자.
<template>
<div>
<button @click="increment"> Click {{state.count}} </button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
const state = reactive({ count: 0 })
const increment = () =>{
state.count++;
}
return {
state, increment
}
}
}
</script>
버튼을 클릭하면, state.count의 값이 +1로 증가하며, 데이터 변경을 감지하여 새롭게 바뀐 데이터값이 화면에 자동으로 업데이트 된다.
변경된 데이터 값을 렌더링 해주는 작업을 하지 않아도 되는 것이다.
이것을 '반응형 상태'라고 부른다.
반응형 상태를 선언하기 위한 방법에는 reactive, ref가 있다.
- 원본 객체에 대한 Proxy를 제공해서 객체에 대한 반응성을 제공.
- Object, Array, Map, Set과 같은 타입에 사용.
- .value를 생략(언래핑)
reactive는 객체나 배열타입의 반응형 상태를 선언하는데 사용된다.
.value 없이 호출 할 수 있다.
<script>
const state = reactive({
count: 0
})
console.log(state.count); // 0출력
</script>
다만, reactive는 기본형(number, string..)타입의 반응형 상태를 유지하지 못한다.
이것이 ref와 가장 큰 차이점이다.
<script>
let state = reactive('Hello World!');
const add = () => {
state = state + '!';
}
console.log(typeof state); //string
</script>
state 변수의 타입을 출력해보면 string으로 나온다.
즉, add함수를 통해 state = state + '!'를 연속적으로 실행시켜도 'Hello World!'만 출력될 것이다.
데이터 자체를 새롭게 할당하기 때문이다.
'Hello World!!'가 출력되기 위해서는 template의 {{state}}와 script의 state가 같은 메모리 주소를 참조해야 하는데, 값 자체가 새롭게 할당되므로 기존의 데이터에 '!'를 추가할 수 없는 것이다.
reactive에서 String과 같은 기본형 타입의 반응형을 유지하기 위해서는 reacitve({value:'Hello World!'})로 선언한 후, state.value로 같은 메모리 주소에 접근해야 한다.
- 객체 타입은 물론 Primitive Type(number, string, boolean ...)까지 모든 타입에 대한 반응성을 제공.
- 내부적으로 value라는 키값에 파라미터를 매핑하는 객체.
- .value로 접근
ref는 기본타입을 반응형 상태로 선언하는데 사용 가능하다.
ref는 변이가능한(반응하는) 객체를 반환하는데, 이 객체 안에는 value라는 단 하나의 속성만 포함한다. value값은 ref() 메서드에서 매개변수로 받은 값을 갖고 있다.
즉, 이 객체는 내부의 value 값에 대한 반응형 참조(reference) 역할을 한다.
<script>
const count = ref(0)
count.value++
console.log(count.value) // 1
</script>
반응형 상태는 어떻게 변경된 데이터를 감지하고 반응하여 업데이트 하는 것일까?
바로, Proxy를 통해서이다.
Proxy는 특정 객체를 감싸 프로퍼티 읽기, 쓰기와 같은 객체에 가해지는 작업을 중간에서 가로채는 객체로, 가로채진 작업은 Proxy 자체에서 처리되기도 하고, 원래 객체가 처리하도록 그대로 전달되기도 한다.
자바스크립트 Object를 만들면 기본적으로 접근자 프로퍼티라고 해서 getter와 setter 함수가 자동으로 포함된다. 바로 get(), set() 함수이다. Proxy를 통해 Object의 get() / set() 메소드를 재정의해서 우리가 원하는 동작을 만들 수 있다. 바로 이부분이 Vue 반응성의 핵심이다.
즉, Vue에서 반응형 상태 객체를 Proxy 객체로 만들어서 값이 바뀌는 동작이 일어나는 set()이 호출되고, set() 핸들러에서 DOM을 업데이트하는 동작을 시키는 것이다. 핵심 개념은 이렇게 아주 간단하다.
다음 그림을 통해 과정을 살펴보자.
💡 여기에서, 반응형 데이터는 모든 변경사항을 적용 시킬까?
그렇지 않다.
Vue는 DOM 업데이트를 비동기로 한다.