Ch 01. Vue 3 Composition API 심화
Composition API를 처음 접하면 ref와 reactive 중 어느 것을 써야 할지 막막합니다. "둘 다 반응형 데이터를 만드는데 왜 두 가지가 존재하는 걸까?"라는 의문이 자연스럽게 떠오릅니다. 실전 선택 기준부터 시작해서 computed, watch, watchEffect까지 차례로 살펴보겠습니다.
ref vs reactive 실전 선택 기준
가장 간단한 기준은 다음과 같습니다. 숫자, 문자열, 불리언처럼 원시값(primitive)을 다룰 때는 ref를 사용합니다. 객체나 배열처럼 참조형 값을 다룰 때는 reactive를 사용합니다.
ref는 .value를 통해 접근하기 때문에 템플릿에서는 자동으로 언래핑되지만, 스크립트 안에서는 항상 .value를 붙여야 합니다. 반면 reactive는 일반 객체처럼 프로퍼티에 직접 접근할 수 있습니다.
const count = ref<number>(0)const user = reactive<{ name: string; age: number }>({ name: '', age: 0 })// ref는 .value로 접근count.value++// reactive는 직접 접근user.name = '홍길동'user.age = 30
computed의 getter와 setter
computed는 기본적으로 읽기 전용이지만, getter와 setter를 함께 정의하면 쓰기도 가능합니다. 폼에서 파생 값을 양방향으로 다룰 때 특히 유용합니다.
const count = ref<number>(0)const doubled = computed({ get: () => count.value * 2, set: (val: number) => { count.value = val / 2 }})doubled.value = 10 // count.value가 5로 변경됩니다.
watch vs watchEffect
watch는 특정 소스를 명시적으로 감시하고, 이전 값과 새 값 모두에 접근할 수 있습니다. watchEffect는 콜백 안에서 참조하는 반응형 데이터를 자동으로 추적하며, 컴포넌트 마운트 시 즉시 실행된다는 차이가 있습니다.
const count = ref<number>(0)const doubled = computed(() => count.value * 2)// 이전 값과 새 값을 모두 받을 수 있습니다.watch(count, (newVal, oldVal) => { console.log(`${oldVal} → ${newVal}`)})// 의존성을 자동으로 추적합니다.watchEffect(() => { console.log(`현재 doubled 값: ${doubled.value}`)})
언제 무엇을 쓸지 헷갈린다면 이렇게 기억하면 됩니다. 이전 값이 필요하거나 감시 대상을 직접 지정하고 싶으면 watch, 단순히 "이 값이 바뀔 때마다 뭔가를 실행하고 싶다"면 watchEffect를 선택합니다.
toRefs와 toRef로 반응성 유지하기
reactive 객체를 구조분해하면 반응성이 깨집니다. 이 문제를 toRefs나 toRef로 해결할 수 있습니다.
const user = reactive<{ name: string; age: number }>({ name: '홍길동', age: 30 })// 구조분해 시 반응성 유지const { name, age } = toRefs(user)// 단일 프로퍼티만 ref로 변환const nameRef = toRef(user, 'name')// 이후 name.value, age.value로 접근합니다.name.value = '김철수'
toRefs는 객체 전체를 한 번에 변환하고, toRef는 특정 프로퍼티 하나만 ref로 만들 때 사용합니다.