Vue.js 를 배워보자
Vue 3 Composition API 완전 정복: ref, reactive, methods, v-model 그리고 스프레드 연산자
_Blue_Sky_
2025. 2. 22. 17:00
728x90
728x90

VUE3의 Composition API는 Vue.js에서 컴포넌트 로직을 더 유연하고 재사용 가능하게 작성할 수 있도록 설계된 새로운 API입니다. 기존의 Options API (data, methods, computed 등)와 달리, Composition API는 컴포넌트의 로직을 기능별로 묶어서 관리할 수 있게 해줍니다. 여기서는 질문에서 요청한 ref, reactive, methods, v-model에 대해 자세히 설명하겠습니다.
1. ref
-
정의: ref는 반응형 데이터(reactivity)를 제공하는 가장 기본적인 방법으로, 단일 값(원시 타입 또는 객체)을 반응형으로 만들 때 사용됩니다.
-
사용법: ref로 정의된 값은 .value 속성을 통해 접근합니다. 템플릿에서는 자동으로 .value가 생략됩니다.
-
예제:
import { ref } from 'vue'; export default { setup() { const count = ref(0); // 반응형 변수 생성 const increment = () => { count.value++; // .value로 값 변경 }; return { count, // 템플릿에서 {{ count }}로 사용 가능 increment, }; }, };
-
특징:
-
원시 타입(숫자, 문자열 등)과 객체 모두 감쌀 수 있음.
-
.value를 통해 내부 값에 접근하지만, 템플릿에서는 생략 가능.
-
반응형 프록시로 작동하며 값이 변경되면 UI가 자동으로 업데이트됨.
-
2. reactive
-
정의: reactive는 객체 또는 배열과 같은 복합 데이터 구조를 반응형으로 만들 때 사용됩니다. ref와 달리 .value가 필요 없습니다.
-
사용법: reactive로 감싼 객체의 속성을 직접 수정하면 반응형이 유지됩니다.
-
예제:
import { reactive } from 'vue'; export default { setup() { const state = reactive({ name: 'John', age: 30, }); const updateName = () => { state.name = 'Jane'; // 직접 수정 가능 }; return { state, updateName, }; }, };
-
특징:
-
객체나 배열에만 적용 가능(원시 타입은 ref 사용).
-
깊은 반응형(deep reactivity)을 제공하여 중첩된 속성도 반응형으로 동작.
-
reactive 객체를 재할당하면 반응형이 깨지므로 주의 (state = {}는 안 됨).
-
3. methods
-
정의: Composition API에서 "methods"라는 별도의 객체는 존재하지 않습니다. 대신 setup() 함수 내에서 일반 JavaScript 함수로 로직을 정의하고, 이를 반환하여 템플릿에서 호출할 수 있습니다.
-
사용법: 함수를 정의하고 return으로 노출하면 됩니다.
-
예제:
import { ref } from 'vue'; export default { setup() { const count = ref(0); // 메소드처럼 동작하는 함수 const increment = () => { count.value++; }; const decrement = () => { count.value--; }; return { count, increment, decrement, }; }, };
-
템플릿에서 사용:
<button @click="increment">증가</button> <button @click="decrement">감소</button> <p>Count: {{ count }}</p>
-
특징:
-
Options API의 methods와 달리, 함수가 setup() 안에서 정의되며, 반응형 데이터(ref, reactive)와 결합해 사용.
-
로직을 기능별로 분리하거나 재사용 가능한 컴포저블(composable)로 만들기 쉬움.
-
4. v-model
-
정의: v-model은 양방향 데이터 바인딩을 제공하는 디렉티브로, Composition API에서도 동일하게 사용됩니다. ref와 결합하여 입력 요소와 반응형 데이터를 연결합니다.
-
사용법: v-model은 내부적으로 value와 input 이벤트를 사용하며, ref로 정의된 변수와 연결됩니다.
-
예제:
import { ref } from 'vue'; export default { setup() { const inputValue = ref(''); // 반응형 변수 const updateValue = () => { console.log('입력값:', inputValue.value); }; return { inputValue, updateValue, }; }, };
-
템플릿:
<input v-model="inputValue" @input="updateValue" /> <p>입력값: {{ inputValue }}</p>
-
커스텀 컴포넌트에서 v-model:
-
부모 컴포넌트에서 자식 컴포넌트에 v-model을 사용할 경우, 자식은 modelValue prop과 update:modelValue 이벤트를 사용.
-
예제 (자식 컴포넌트):
export default { props: ['modelValue'], emits: ['update:modelValue'], setup(props, { emit }) { const update = (event) => { emit('update:modelValue', event.target.value); }; return { update }; }, };
<input :value="modelValue" @input="update" />
-
부모 컴포넌트:
<CustomInput v-model="inputValue" />
-
-
특징:
-
ref와 함께 사용하면 간단히 양방향 바인딩 구현 가능.
-
커스텀 컴포넌트에서는 v-model을 prop과 이벤트로 확장 가능.
-
추가 팁
-
ref vs reactive:
-
ref는 단일 값이나 객체에 적합, .value 필요.
-
reactive는 객체/배열에 적합, 속성 직접 수정 가능.
-
-
컴포저블(Composable):
-
Composition API의 강력한 기능으로, 로직을 별도의 함수로 분리해 재사용 가능.
-
예: useCounter.js
import { ref } from 'vue'; export function useCounter() { const count = ref(0); const increment = () => count.value++; return { count, increment }; }
import { useCounter } from './useCounter'; export default { setup() { const { count, increment } = useCounter(); return { count, increment }; }, };
-
결론
Vue 3의 Composition API는 ref와 reactive로 반응형 데이터를 관리하고, setup()에서 함수를 정의해 "methods"처럼 사용하며, v-model로 양방향 바인딩을 쉽게 구현할 수 있습니다. Options API보다 코드 구조화와 재사용성이 뛰어나며, 대규모 프로젝트에서 특히 유리합니다. 질문이 더 있다면 언제든 물어보세요!
728x90
Vue 3의 Composition API에서 스프레드 연산자(...)를 사용하는 방법을 보여드리겠습니다. 스프레드 연산자는 주로 객체 또는 배열을 복사하거나 병합할 때 유용하며, 반응형 데이터(ref, reactive)와 함께 사용할 수도 있습니다. 아래에서 몇 가지 예제를 통해 설명하겠습니다.
1. reactive와 스프레드 연산자 사용
reactive 객체의 속성을 다른 객체와 병합하거나 복사할 때 스프레드 연산자를 사용할 수 있습니다. 다만, reactive 객체 자체는 프록시로 감싸져 있으므로 스프레드 연산자를 사용하면 반응형이 풀린 일반 객체로 변환됩니다. 이를 다시 reactive로 감싸야 반응형을 유지할 수 있습니다.
예제:
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
name: 'John',
age: 30,
});
// 스프레드 연산자로 객체 병합
const updatedState = reactive({
...state, // 기존 state 복사
city: 'Seoul', // 새 속성 추가
});
return {
state,
updatedState,
};
},
};
템플릿:
<p>원본: {{ state.name }}, {{ state.age }}</p>
<p>업데이트: {{ updatedState.name }}, {{ updatedState.age }}, {{ updatedState.city }}</p>
-
주의: const newState = { ...state }만 하면 반응형이 유지되지 않으므로, 반드시 reactive()로 다시 감싸야 합니다.
2. ref와 스프레드 연산자 사용 (객체 내부)
ref로 객체를 감싼 경우, .value를 통해 내부 객체에 접근한 뒤 스프레드 연산자를 사용할 수 있습니다.
예제:
import { ref } from 'vue';
export default {
setup() {
const user = ref({
name: 'Jane',
age: 25,
});
const updateUser = () => {
user.value = {
...user.value, // 기존 값 복사
age: 26, // 특정 속성 업데이트
};
};
return {
user,
updateUser,
};
},
};
템플릿:
<p>{{ user.name }}, {{ user.age }}</p>
<button @click="updateUser">나이 증가</button>
-
설명: user.value를 스프레드 연산자로 복사한 뒤 새로운 속성을 추가하거나 덮어씌웁니다. ref는 여전히 반응형을 유지합니다.
3. 배열과 스프레드 연산자 사용
ref나 reactive로 관리되는 배열에서도 스프레드 연산자를 활용해 요소를 추가하거나 복사할 수 있습니다.
예제:
import { ref } from 'vue';
export default {
setup() {
const items = ref(['apple', 'banana']);
const addItem = () => {
items.value = [...items.value, 'orange']; // 배열에 새 요소 추가
};
return {
items,
addItem,
};
},
};
템플릿:
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
<button @click="addItem">아이템 추가</button>
-
설명: items.value를 스프레드 연산자로 복사하고 새 요소를 추가하면 반응형 배열이 업데이트됩니다.
4. 컴포저블에서 스프레드 연산자 활용
스프레드 연산자는 컴포저블 함수의 반환값을 병합하거나 재사용할 때도 유용합니다.
예제:
// useUser.js
import { ref } from 'vue';
export function useUser() {
const user = ref({ name: 'Alice', age: 28 });
const updateName = (newName) => {
user.value = { ...user.value, name: newName };
};
return { user, updateName };
}
// 컴포넌트
import { useUser } from './useUser';
export default {
setup() {
const { user, updateName } = useUser();
const extendedUser = ref({
...user.value, // useUser에서 가져온 객체 복사
city: 'Tokyo',
});
return {
user,
extendedUser,
updateName,
};
},
};
템플릿:
<p>원본: {{ user.name }}, {{ user.age }}</p>
<p>확장: {{ extendedUser.name }}, {{ extendedUser.age }}, {{ extendedUser.city }}</p>
<button @click="updateName('Bob')">이름 변경</button>
-
설명: useUser에서 가져온 반응형 데이터를 스프레드 연산자로 확장하여 새로운 객체를 만듭니다. 단, extendedUser는 독립적인 ref이므로 user 변경 시 연동되지 않음에 주의하세요.
주의사항
-
반응형 유지: reactive 객체에 스프레드 연산자를 사용하면 반응형이 깨지므로, 결과물을 reactive()로 다시 감싸야 합니다.
-
얕은 복사: 스프레드 연산자는 얕은 복사(shallow copy)를 수행하므로, 중첩된 객체는 참조가 유지됩니다. 깊은 복사가 필요하면 별도의 로직(예: JSON.parse(JSON.stringify()))을 사용하세요.
-
성능: 대량의 데이터를 다룰 때는 스프레드 연산자가 성능에 영향을 줄 수 있으니 적절히 사용하세요.
728x90
위 예제들을 통해 ref, reactive, 배열, 컴포저블 등 다양한 상황에서 스프레드 연산자를 사용하는 방법을 확인할 수 있습니다. 추가로 궁금한 점이 있다면 말씀해주세요!
728x90
728x90