ref()
- 기본 타입(primitive) 값이나 객체를 반응형으로 만들기 위한 함수
- .value를 통해 접근하고 수정해야 함
- 템플릿에서는 .value 없이도 자동 언래핑됨
- ref()로 감싼 객체의 중첩된 속성까지 자동으로 반응형이 됨
<template>
<div>
<h1>Count: {{ count }}</h1>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { ref } from "vue";
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
참고
reactive()
와ref()
언래핑 (객체 내부)reactive()
로 감싼 객체 속성 내부에ref
가 있을 경우,ref
는 자동으로 언래핑되어 템플릿이나 코드에서.value
없이 사용할 수 있음const state = reactive({ count: ref(1), name: ref("Vue"), }); console.log(state.count); // 1
reactive()
와ref()
언래핑 (배열 내부)reactive()
로 감싼 배열 내에ref
가 있을 경우, 배열은 언래핑되지 않음배열의 요소들은
ref
객체로 남기 때문에.value
를 명시적으로 사용해야 함const list = reactive([ref(1), ref(2)]); console.log(list[0]); // ref(1) console.log(list[0].value); // 1
reactive()
와ref()
언래핑 (Map
내부)reactive()
로 감싼Map
객체 안에ref
를 포함시킬 때,ref
는 자동으로 언래핑되지 않음map.get('count')
는ref
객체로 그대로 나오므로,.value
를 통해 접근해야 한다.const map = reactive(new Map([["count", ref(1)]])); console.log(map.get("count")); // ref(1) console.log(map.get("count").value); // 1
ref()
와ref()
언래핑ref
로 감싼 객체 내부에 또 다른ref
객체가 있을 경우, 내부ref
는 자동으로 언래핑되어.value
없이 그 값을 사용할 수 있음const obj = ref({ name: ref("Kim"), }); console.log(obj.value.name); // 'Kim'
객체 리터럴과
ref()
언래핑reactive()
을 사용하지 않은 객체 리터럴 내부에ref
가 있을 경우,ref
객체를 템플릿에서 사용할 때value
를 명시적으로 써야 함<template> <div> <p>Count: {{ state.count }}</p> <p>Name: {{ state.name }}</p> <button @click="increment">+</button> </div> </template> <script> import { ref } from "vue"; export default { setup() { const state = { count: ref(1), name: ref("Vue"), }; const increment = () => { state.count.value++; }; return { state, increment, }; }, }; </script>
reactive()
- 객체를 반응형으로 만들어주는 함수
- .value 없이 바로 접근할 수 있음
- reactive()로 감싼 객체의 중첩된 속성까지 자동으로 반응형이 됨
<template>
<p>Count: {{ state.count }}</p>
<p>Name: {{ state.name }}</p>
<button @click="increment">+</button>
</template>
<script setup>
import { reactive } from "vue";
const state = reactive({
count: 0,
name: "Vue",
});
function increment() {
state.count++;
}
</script>
readonly()
- 객체를 읽기 전용으로 만들어, 그 객체의 속성 값을 수정할 수 없도록 함
const obj = reactive({ name: "Vue", version: "3.0" });
const readonlyReactiveObj = readonly(obj);
console.log(readonlyReactiveObj.name); // 'Vue'
obj.name = "React";
console.log(readonlyReactiveObj.name); // 'React' (obj의 변경이 반영됨)
readonlyReactiveObj.name = "Angular"; // 오류 발생: "Cannot set property 'name' of a readonly object"
computed()
- 반응형 계산 속성을 만드는 함수
- 자동 계산: computed() 속성은 의존하고 있는 데이터가 변경될 때만 다시 계산됨
- 캐시: 의존하는 값이 변경되지 않는 한, 계산된 결과는 캐시되므로 불필요한 계산을 피할 수 있음
- 읽기 전용: 기본적으로 computed() 속성은 읽기 전용이기 때문에 값을 설정하려면 set 함수를 명시적으로 제공해야 함
const number1 = ref(10);
const number2 = ref(20);
const sum = computed(() => {
return number1.value + number2.value;
});
console.log(sum.value); // 30
number1.value = 15;
console.log(sum.value); // 35
- computed()는 기본적으로 읽기 전용이지만, set과 get을 사용하면 읽기/쓰기가 가능한 계산된 속성을 만들 수 있음
const firstName = ref("");
const lastName = ref("");
const fullName = computed({
get(prevName) {
return `${firstName.value} ${lastName.value}`;
},
set(newName) {
const names = newName.split(" ");
firstName.value = names[0];
lastName.value = names[1];
},
});
fullName.value = "John Doe"; // set이 호출되어 firstName과 lastName이 업데이트됨
console.log(firstName.value); // 'John'
console.log(lastName.value); // 'Doe'
watch()
- 특정 반응형 데이터를 감시하고, 값이 변할 때 어떤 코드를 실행하는 함수
- 감시할 것: ref, reactive, computed, getter 함수, 배열 가능
- 콜백함수: (newValue, oldValue) => {} 형태
- 옵션: { immediate, deep, flush, once, ... }
watch(감시할것, 콜백함수, 옵션);
- getter 감시
const state = reactive({ count: 0 });
watch(
() => state.count, // state.count는 숫자이기 때문에 getter을 써야 함
(count, prevCount) => {
console.log(`count 변경: 이전 값 = ${prevCount}, 새로운 값 = ${count}`);
}
);
- ref 감시
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`count 변경: 이전 값 = ${oldValue}, 새로운 값 = ${newValue}`);
});
- 배열 감시
const fooRef = ref(0);
const barRef = ref(0);
watch([fooRef, barRef], ([newFoo, newBar], [oldFoo, oldBar]) => {
console.log(`foo: 이전 = ${oldFoo}, 새로운 = ${newFoo}`);
console.log(`bar: 이전 = ${oldBar}, 새로운 = ${newBar}`);
});
- 객체(reactive) 감시
const state = reactive({ count: 0, nested: { value: 10 } });
watch(
() => state, // state도 가능
(newValue, oldValue) => {
console.log("state 객체 변경됨");
},
{ deep: true } // 깊이도 설정 가능
);
옵션 설정
옵션 이름 기본값 설명 immediate false watch 등록하자마자 바로 실행할지 결정 (바로 실행하면 oldValue는 undefinded) deep false 객체 내부까지 감시할지 결정 flush 'pre' DOM 업데이트 전에 실행 (pre), DOM 업데이트 후에 실행 (post), 즉시 실행 (sync) 할지 결정 onTrack undefined 디버깅용, 기본적으로 아무것도 안함 onTrigger undefined 디버깅용, 기본적으로 아무것도 안함 once false 한 번만 실행할지 결정
watchEffect()
- 함수 안에서 읽은 반응형 데이터를 알아서 추적해서, 값이 변하면 다시 실행하는 함수
- 기본적으로 watch() 와 비교했을 때, immediate = true, deep = true 임
- 동기적 실행 동안에만 종속성을 추적하기 때문에 비동기 콜백과 함께 사용할 때는 첫 번째 await 틱 전에 접근한 속성만 추적됨됨
- 함수: 안에서 읽은 반응형 값들을 자동으로 감시해줌
- 옵션: { flush, onTrack, onTrigger, once }
watchEffect(함수, 옵션);
const count = ref(0);
watchEffect(() => {
console.log(`count 값은 ${count.value} 입니다.`);
});
참고
watch()나 watchEffect()는 기본적으로 동기적으로 생성되어야 함
만약 비동기 콜백 내에서 생성되면 소유자 컴포넌트에 바인딩되지 않으며, 메모리 누수를 피하기 위해 수동으로 중지해야 함
수동으로 중지하려면 반환된 핸들 함수를 사용
// 이 감시자는 자동으로 중지
watchEffect(() => {});
// 이 감시자는 중지되지 않음
setTimeout(() => {
watchEffect(() => {});
}, 100);
const unwatch = watchEffect(() => {});
// 나중에, 더 이상 필요하지 않을 때
unwatch();
watchPostEffect()
- watchEffect()에서 flush: 'post' 옵션 사용
watchSyncEffect()
- watchEffect()에서 flush: 'sync' 옵션 사용
onWatcherCleanup()
- watch()나 watchEffect()안에서,다음 콜백 실행 직전에 정리(cleanup) 작업을 등록할 수 있게 해주는 함수
const count = ref(0);
watchEffect(() => {
console.log("watchEffect 실행됨");
const timer = setInterval(() => {
console.log("타이머 돌아가는 중");
}, 1000);
onWatcherCleanup(() => {
clearInterval(timer);
console.log("타이머 정리 완료");
});
});
참고
비동기 작업(예: fetch)을 watch()나 watchEffect() 내부에서 실행하면, 이전 watch가 아직 끝나기도 전에 다음 watch가 실행될 수 있음
때문에 오래된 fetch 요청을 취소하거나 정리 작업(cleanup)을 해야 함
- onWatcherCleanup()
onWatcherCleanup()은 Vue 3.5 이상에서만 사용 가능
동기 코드 안에서만 호출 가능
await 이후에는 onWatcherCleanup()을 호출하면 경고나 오류가 남
import { watch, onWatcherCleanup } from "vue";
watch(id, (newId) => {
const controller = new AbortController();
fetch(`/api/${newId}`, { signal: controller.signal });
// 이 watch가 무효화되면 호출됨
onWatcherCleanup(() => {
controller.abort(); // 이전 요청 취소
});
});
- onCleanup()
Vue 3.0 이상에서 사용 가능
비동기 함수 안에서도 호출 가능
await 이후에도 호출 가능
watch(id, (newId, oldId, onCleanup) => {
const controller = new AbortController();
fetch(`/api/${newId}`, { signal: controller.signal });
onCleanup(() => {
controller.abort(); // 이전 요청 취소
});
});
출처: 짐코딩, 「Vue3 완벽 마스터: 기초부터 실전까지 - "기본편"」, 인프런
출처: Vue.js
'Web > Vue' 카테고리의 다른 글
Non-Prop Attributes (0) | 2025.05.02 |
---|---|
Props (0) | 2025.05.02 |
Components (0) | 2025.05.02 |
Vue.js 프로젝트 구조 (0) | 2025.04.23 |
Vue.js 시작하기 (0) | 2025.04.23 |