일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- abstract
- array
- ArrayList
- Class
- collection
- coposition api
- csr
- database
- db
- DDL
- default
- DML
- Exception
- Generic
- HashSet
- Interface
- Java
- Java 입문
- java 자료형
- java 클래스
- JavaBean
- javabeans
- JAVA의 특징
- JSESSIONID
- LinkedList
- linkedset
- list
- mariadb
- Mpa
- Mustache
- Today
- Total
GeehDev
[Vue3] 반응형 데이터 : ref() 와 reactive() 본문
Index
반응형 데이터
Vue에서 반응형 데이터(Reactivity) 란, 데이터가 변경될 때 자동으로 UI가 업데이트되는 데이터를 의미한다.
데이터가 변하거나 특정 조건이 되었을 때 직접 UI에 이를 적용해주던 기존 방식보다 훨씬 간편하게 UI를 조작 및 관리할 수 있다.
기존방식
<p> 이름 : <strong id="userNm"></strong> </p>
<input type="text" name="userNm" placeholder="이름을 입력하세요" />
<script>
document.querySelector('input[name=userNm]').eventListener('input', ()=>{
document.getElementById('userNm').innerText = this.value;
});
</script>
Vue의 반응형 데이터 방식
<template>
<p> 이름 : <strong id="userNm">{{ userNm }}</strong> </p>
<input type="text" name="userNm" placeholder="이름을 입력하세요" v-model="userNm" />
</template>
<script setup lang="ts">
import { ref } from "vue";
const userNm = ref('');
</script>
Vue3에서는 이러한 반응형 데이터를 사용하는 대표적인 방법으로 ref()
, reactive()
가 있다.
ref()
<template>
<p>{{ count }}</p>
<button @click="count.value++">+1</button>
</template>
<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
</script>
- reference 라는 의미로 반응형 데이터를 만들고, 해당 값을 참조할 수 있도록 해주는 함수
- 기본형, 객체, 배열 등의 모든 자료형을 감쌀 수 있다.
- 주로 기본형 타입을 담는데 유리하다.
- 생성 후 값에 접근할 때는
변수.value
로 접근해줘야한다. - 값 자체가 변경될 때, 객체 또는 배열에서 내부 값 또는 속성이 변경될 때 모두 감지할 수 있음
reactive()
<template>
<p v-for="(item, id) of obj" :key="id">저의 {{id}} 은/는 {{item}} 입니다.</p>
</template>
<script setup lang="ts">
import { reactive } from "vue";
const obj = reactive({"이름": "geehdev", "직업": "developer", "취미": "game"});
</script>
- ref와 마찬가지로 반응형 데이터를 만드는 함수로, 배열, 객체 등 객체의 반응형 상태관리에 유리하다.
- 생성 후 값에 접근할 때는
.value
없이 직접 접근이 가능하다. - 값 내부 속성이 변경될 때 업데이트를 감지하며, 값 자체가 변경될 때는 반응성 성질을 잃는다.
ref() vs reactive()
모두 vue에서 반응형 데이터를 만들고, 반응형 상태관리를 할 수 있지만, 사용목적과 동작방식에 따라 차이점이 있다.
1. 사용 타입
ref()
, reactive()
모두 모든 타입을 대입할 수는 있으나, 업데이트 감지 범위와 반응성 유지 여부가 달라 각 각 주로 사용되는 타입이 다르다.
- ref() : 기본타입을 대입에 사용된다. (값 자체의 변경을 감지하기 때문)
- reactive() : 배열, 객체 타입을 대입에 주로 사용된다. (값 내부 속성의 변화를 감지하기 때문)
예시
ref()
<!-- ref -->
<script setup lang="ts">
const ref1 = ref('ref 입니다.');
const ref2 = ref(12345);
const ref3 = ref({'key1' : 'value1', 'key2' : 'value2'});
const ref4 = ref([1,2,3,4,5,6,7]);
</script>
<template>
<strong>1. 기본형</strong>
<p>ref1 = {{ref1}}</p>
<p>ref2 = {{ref2}}</p>
<strong>2. 객체</strong>
<p>{{ ref3 }}</p>
<p v-for="(value, key) in ref3">ref3[{{ key }}] = {{ value }}</p>
<strong>3. 배열</strong>
<p>{{ ref4 }}</p>
<p v-for="(item, idx) in ref4">ref4[{{ idx }}] = {{ item }}</p>
</template>
reactive()
<!-- reactive -->
<script setup lang="ts">
const reactive1 = reactive({"name" : "지현", "age" : 0, "arr": []});
const reactive2 = reactive([1,2,3,4,5,6,7]);
let reactive3 = reactive(0); // 기본타입의 경우 대입은 가능하나, 값 변경될 시 감지 못함 => 반응형 데이터 특성을 잃음(아래 참고)
let reactive4 = reactive("test"); // 기본타입의 경우 대입은 가능하나, 값 변경될 시 감지 못함 => 반응형 데이터 특성을 잃음(아래 참고)
</script>
<template>
<p>{{ reactive1 }}</p>
<p>{{ reactive2 }}</p>
<p>{{ reactive3 }}</p>
<p>{{ reactive4 }}</p>
</template>
2. 업데이트 감지 범위와 반응성 유지 여부
- ref()
- 내부적으로 Object.defineProperty()를 사용하여 .value의 변경을 추적
- 대입된 값 자체의 변경을 감지한다.
- reactive()
- Vue의 Proxy 기반으로 객체의 변화를 추적
- 대입된 값 내부 속성의 변화를 감지한다.
- 값 자체게 변경될 경우 반응성 성질을 잃고 변화를 감지하지 못하게된다. (기본형 타입에 사용하지 않는 이유)
예시
ref()
<!-- ref -->
<script setup lang="ts">
let obj = ref({"name" : "지현", "age" : 0});
const changeAgeOnly = (add:number) => {
obj.value.age = obj.value.age + add;
};
const changeObj = (name:string, age:number) => {
obj.value = ref({"newName" : name, "newAge" : age});
}
</script>
<template>
<p> obj = {{ obj }}</p>
<strong>1. 값의 속성만 변경</strong>
<button @click="changeAgeOnly(10)">나이 10살 더하기</button> <!-- 업데이트 감지함 -->
<strong>2. 값 자체를 변경</strong>
<button @click="changeObj('새로운 지현', 200)">객체를 바꾸기</button> <!-- 업데이트 감지함 -->
</template>
reactive()
<!-- reactive -->
<script setup lang="ts">
const reactive1 = reactive({"name" : "지현", "age" : 0, "arr": []});
const reactive2 = reactive([1,2,3,4,5,6,7]);
let reactive3 = reactive(0); // 기본타입의 경우 대입은 가능하나, 값 변경될 시 감지 못함 => 반응형 데이터 특성을 잃음(아래 참고)
let reactive4 = reactive("test"); // 기본타입의 경우 대입은 가능하나, 값 변경될 시 감지 못함 => 반응형 데이터 특성을 잃음(아래 참고)
const selectVar = ref('');
const inputText = ref('');
const changeReactive = (idx) => {
if(idx === 1) {
reactive1["name"] = '변경된 값';
reactive1["age"] = '20';
reactive1["etc"] = '기타';
reactive1["arr"].push(1)
}
if(idx === 2) {
reactive2.push(100);
}
if(idx === 3) {
reactive3 = 'reactive3 변경';
}
if(idx === 4) {
reactive4 = 'reactive4 변경';
}
};
</script>
<template>
<p>{{ reactive1 }}</p>
<p>{{ reactive2 }}</p>
<p>{{ reactive3 }}</p>
<p>{{ reactive4 }}</p>
<button @click="changeReactive(1)">reactive1 값 변경</button>
<button @click="changeReactive(2)">reactive2 값 변경</button>
<button @click="changeReactive(3)">reactive3 값 변경</button> <!-- 값이 변경되긴하나, 업데이트를 감지하지 못해 UI변화 없음 -->
<button @click="changeReactive(4)">reactive4 값 변경</button> <!-- 값이 변경되긴하나, 업데이트를 감지하지 못해 UI변화 없음 -->
</template>
3. 데이터 접근 방식
- ref()
- 기본적으로 값에 접근할 때는
.value
로 접근한다. - 단, template 내부에서는 Auto Unwrapping 으로 변수명으로 직접 접근한다.
- 기본적으로 값에 접근할 때는
- reactive()
.value
없이 직접 접근한다.
예시
ref()
<script setup lang="ts">
// ref : 3-1. template 내에서 값 접근 : Auto Unwrapping
const count1 = ref(0);
// ref : 3-2. template 외부 에서의 값 접근 : .value로 접근
let count2 = ref(0);
const add1UseValue = () => { count2.value++;};
const add1NotUseValue = () => { count2++; };
</script>
<template>
<!-- ref : 3-1. template 내에서 값 접근 : Auto Unwrapping -->
<p>count = {{ count1 }}</p>
<strong>1. 직접 접근</strong>
<button @click="count1++">count1++</button>
<strong>2. .value로 접근 => error 발생</strong>
<button @click="count1.value++">count1.value++</button>
<!-- ref : 3-2. template 외부 에서의 값 접근 : .value로 접근 -->
<p>count = {{ count2 }}</p>
<strong>1. 직접 접근 => 반응형 특성 잃음</strong>
<button @click="add1NotUseValue()">add1NotUseValue</button>
<strong>2. .value로 접근</strong>
<button @click="add1UseValue()">add1UseValue</button>
</template>
reactive()
<script setup lang="ts">
// reactive : 3. 어디서든 변수로 바로 접근
const arr = reactive([1,2,3,4,5]);
const addArr = ()=> {
arr.push(arr.length + 1);
}
</script>
<template>
<!-- reactive : 3. 어디서든 변수로 바로 접근 -->
<p v-for="item of arr">{{ item }}</p>
<button @click="addArr">arr push</button>
</template>
4. 구조분해할당 처리 방식
기본적으로 ref()
, reactive()
로 할당된 반응형 데이터를 구조분해할당할 경우 구조분해할당된 변수에서는 기존 반응형 성질을 잃게된다.
그러나 toRefs()
를 사용하여 구조분해할당한 변수도 ref
변수로 만들어 사용할 수 있다.
예시
ref()
<script setup lang="ts">
// ref : 4. 구조분해할당 사용
let cnt = 0;
const refObj = ref({"name" : "지현", "age" : 0});
let {name: objName, age: objAge} = refObj.value; // 일반 변수로, 반응형 성질 없음
let {name: objName2, age: objAge2} = toRefs(refObj.value); // toRef()를 사용하여 ref 변수로 생성
const changeObjName = () => {
refObj.value["name"] = refObj.value["name"] + cnt;
refObj.value["age"] = refObj.value["age"] + cnt;
cnt ++;
};
</script>
<template>
<!-- ref : 4. 구조분해할당 사용 -->
<p>refObj : {{ refObj }}</p>
<p>objName : {{ objName }}</p> <p>objAge : {{ objAge }}</p> <!-- 일반 데이터로 refObj 변경될 시 같이 변경 안 됨 -->
<p>objName2 : {{ objName2 }}</p> <p>objAge2 : {{ objAge2 }}</p> <!-- 반응형 데이터로 refObj 변경될 시 같이 변경 됨 -->
<button @click="changeObjName">refObj 값 변경</button>
</template>
reactive()
<script setup lang="ts">
// reactive : 4. 구조분해할당 사용
let cnt2 = 0;
const reactiveObj = reactive({"name" : "지현", "age" : 0});
const {name : reactiveObjName, age: reactiveObjAge} = reactiveObj; // 일반 변수로, 반응형 성질 없음
const {name : reactiveObjName2, age: reactiveObjAge2} = toRefs(reactiveObj); // toRef()를 사용하여 ref 변수로 생성
const changeReactiveObjName = () => {
reactiveObj["name"] = reactiveObj["name"] + cnt2;
reactiveObj["age"] = reactiveObj["age"] + cnt2;
cnt2++;
};
</script>
<template>
<!-- reactive : 4. 구조분해할당 사용 -->
<p>reactiveObj : {{ reactiveObj }}</p>
<p>reactiveObjName {{ reactiveObjName }}</p> <p>reactiveObjAge {{ reactiveObjAge }}</p> <!-- 일반 데이터로 refObj 변경될 시 같이 변경 안 됨 -->
<p>reactiveObjName2 {{ reactiveObjName2 }}</p> <p>reactiveObjAge2 {{ reactiveObjAge2 }}</p> <!-- 반응형 데이터로 refObj 변경될 시 같이 변경 됨 -->
<button @click="changeReactiveObjName">reactiveObj 속성 값 변경</button>
</template>
요약
항목 | ref() | reactive() |
주 사용 타입 | 원시 타입 (string , number , boolean ) |
객체, 배열 |
반응성 감지 방식 | .value 의 변경을 감지 ( Object.defineProperty 사용) |
Proxy 기반으로 내부 속성 변경을 감지 |
값 변경 감지 여부 | 값 자체의 변경을 감지 | 내부 속성 변경을 감지하지만, 객체 자체를 변경하면 반응성을 잃음 |
템플릿 내부에서 접근 방식 | - 변수명으로 직접 접근 (Auto Unwrapping 지원) |
변수명으로 직접 접근 |
템플릿 외부에서 접근 방식 | .value 로 접근해야 함 (refVar.value ) |
.value 없이 직접 접근 가능 |
배열, 객체 사용 여부 | 가능하지만 .value 필요 |
.value 없이 바로 사용 가능 |
구조 분해 시 반응성 유지 여부 | const { x } = refObj.value; → ❌ 반응성 깨짐const { x } = toRefs(refObj.value); → ✅ 반응성 유지됨 |
마치며
vue에서 가장 강력한 기능인 반응형 데이터를 사용하는 기초적인 방식에 대해서 공부하고 정리해봤다.
정리하면서 ref와 reactive를 사용할 때 각각 정확히 어떤 상황에서 사용하는 것이 유리한 가에 초점을 두고 알아봤는데, ref의 경우 비교적 간단하게 기본형 타입에 대해 값을 바인딩 해줄때 사용하고, reacive는 객체, 배열을 담아서 사용할 때 유리하다고 생각된다.
'Study > Vue.js' 카테고리의 다른 글
[Vue3] Vue 템플릿 문법 (Mustache, Directive) (0) | 2025.03.02 |
---|---|
[Vue3] Vue.js 소개 및 개발환경 셋팅 (0) | 2025.02.24 |