Pinia Store에서 ref와 reactive를 사용하는 방법
Pinia Store에서 ref와 reactive를 사용하는 방법을 알아보겠습니다.
Pinia에서는 Composition API 스타일과 Options API 스타일을 모두 사용할 수 있지만,
여기서는 Composition API 스타일을 중점적으로 설명합니다.
1. Vue가 뭐야?
2. 프레임워크란?
3. Vue3 기본 문법
4. Vue Router (<router-link>, <router-view>)
5. Pinia (상태 관리 라이브러리)
6. Vue3 Composition API
7. Pinia Store에서 ref와 reactive를 사용하는 방법
8. Pinia에서의 Composition API 스타일과 Options API 스타일
1. ref와 reactive 차이
- ref(): 기본 타입(숫자, 문자열, 불리언 등)이나 객체를 반응형으로 만들 때 사용하며, .value를 통해 값을 접근해야 합니다.
- reactive(): 객체나 배열을 반응형으로 만들 때 사용합니다. .value 없이 바로 속성에 접근할 수 있습니다.
Pinia에서는 state를 ref() 또는 reactive()로 선언하여 사용할 수 있습니다.
2. ref() 사용하기 (Composition API 스타일)
✅ defineStore() 안에서 ref() 사용
ref()를 사용하면 Pinia store의 상태를 반응형으로 만들 수 있습니다.
// src/stores/counter.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
return { count, increment, decrement };
});
✅ 컴포넌트에서 사용하기
<!-- src/components/Counter.vue -->
<template>
<div>
<p>Count: {{ counter.count }}</p>
<button @click="counter.increment">Increment</button>
<button @click="counter.decrement">Decrement</button>
</div>
</template>
<script setup>
import { useCounterStore } from '../stores/counter';
const counter = useCounterStore();
</script>
📌 설명
- defineStore() 내부에서 ref()를 사용하면, count는 반응형 데이터가 됩니다.
- increment()와 decrement()는 count.value를 수정합니다.
- 컴포넌트에서 counter.count를 직접 사용하면 반응형이 자동으로 적용됩니다.
3. reactive() 사용하기 (Composition API 스타일)
✅ defineStore() 안에서 reactive() 사용
reactive()를 사용하면 객체의 여러 속성을 한 번에 반응형으로 만들 수 있습니다.
// src/stores/user.js
import { defineStore } from 'pinia';
import { reactive } from 'vue';
export const useUserStore = defineStore('user', () => {
const user = reactive({
name: 'John Doe',
age: 30,
});
const updateName = (newName) => {
user.name = newName;
};
const incrementAge = () => {
user.age++;
};
return { user, updateName, incrementAge };
});
✅ 컴포넌트에서 사용하기
<!-- src/components/UserProfile.vue -->
<template>
<div>
<p>Name: {{ userStore.user.name }}</p>
<p>Age: {{ userStore.user.age }}</p>
<button @click="userStore.incrementAge">Increase Age</button>
<button @click="userStore.updateName('Alice')">Change Name</button>
</div>
</template>
<script setup>
import { useUserStore } from '../stores/user';
const userStore = useUserStore();
</script>
📌 설명
- reactive()를 사용하면 user 객체 전체가 반응형이 됩니다.
- updateName()을 호출하면 user.name이 변경됩니다.
- incrementAge()를 호출하면 user.age가 증가합니다.
4. ref() vs reactive() 비교
ref()reactive()
데이터 타입 | 기본 값(숫자, 문자열, 불리언, 객체 등) | 객체, 배열 |
접근 방법 | 변수.value | 변수.속성 |
속성 추가 가능 여부 | O (가능) | X (초기 정의된 속성만 반응형) |
객체 구조분해 (destructure) | 반응형 유지 안됨 | 반응형 유지됨 |
💡 주의: reactive()로 만든 객체를 구조 분해하면 반응성을 잃을 수 있습니다.
예제:
const store = useUserStore();
const { name } = store.user; // ❌ 반응형이 깨짐
➡️ 해결 방법: computed()를 사용하거나 store.user.name을 직접 사용.
5. ref()와 reactive() 함께 사용하기
✅ reactive() + ref() 조합
reactive() 내부에서 ref()를 사용할 수도 있습니다.
// src/stores/todo.js
import { defineStore } from 'pinia';
import { reactive, ref } from 'vue';
export const useTodoStore = defineStore('todo', () => {
const todos = reactive([]);
const newTodo = ref('');
const addTodo = () => {
if (newTodo.value.trim()) {
todos.push({ text: newTodo.value, completed: false });
newTodo.value = '';
}
};
return { todos, newTodo, addTodo };
});
✅ 컴포넌트에서 사용하기
<!-- src/components/TodoList.vue -->
<template>
<div>
<input v-model="todoStore.newTodo" placeholder="Add a task" />
<button @click="todoStore.addTodo">Add</button>
<ul>
<li v-for="(todo, index) in todoStore.todos" :key="index">
{{ todo.text }}
</li>
</ul>
</div>
</template>
<script setup>
import { useTodoStore } from '../stores/todo';
const todoStore = useTodoStore();
</script>
📌 설명
- reactive([])로 빈 배열 todos를 생성했습니다.
- ref('')로 newTodo를 생성하여 input과 연결했습니다.
- addTodo()를 실행하면 todos 배열에 새로운 항목이 추가됩니다.
6. persist (상태 저장) 기능과 함께 사용하기
Pinia의 persist 옵션을 사용하면, localStorage 또는 sessionStorage에 상태를 저장할 수 있습니다.
// src/stores/settings.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useSettingsStore = defineStore('settings', () => {
const darkMode = ref(false);
const toggleDarkMode = () => {
darkMode.value = !darkMode.value;
};
return { darkMode, toggleDarkMode };
}, {
persist: true, // localStorage에 저장
});
이제 페이지를 새로고침해도 darkMode 상태가 유지됩니다.
🔹 정리
✅ ref()
- 기본 타입 (숫자, 문자열, 불리언) 및 객체를 반응형으로 만들 때 사용.
- .value를 사용하여 값을 변경하거나 읽어야 함.
✅ reactive()
- 객체, 배열을 반응형으로 만들 때 사용.
- .value 없이 속성에 바로 접근 가능.
- 새로운 속성을 추가하면 반응형이 깨질 수 있음.
✅ reactive()와 ref()를 함께 사용할 수도 있음.
- reactive()는 객체에 적합하고, ref()는 개별 값에 적합함.
✅ persist 옵션을 사용하면 Pinia 상태를 로컬 스토리지에 저장 가능.
이제 Pinia에서 ref()와 reactive()를 자유롭게 활용해볼 수 있습니다! 🚀
다음 : 8. Pinia에서의 Composition API 스타일과 Options API 스타일
'Vue3, Firebase 프로젝트 - 채팅앱 VSignal' 카테고리의 다른 글
20. [개발] 로그인 후 채팅방 이동 - Vue3 Firebase 프로젝트 채팅앱 VSignal (0) | 2025.04.01 |
---|---|
8. Pinia에서의 Composition API 스타일과 Options API 스타일 (0) | 2025.03.30 |
6. Vue3 Composition API (0) | 2025.03.30 |
5. Pinia (상태 관리 라이브러리) (0) | 2025.03.30 |
4. Vue Router (<router-link>, <router-view>) (0) | 2025.03.30 |