상태 관리
여러 하위 컴포넌트들이 동일한 데이터를 사용해야 할 경우
→ 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달해야 할 때 props를 사용합니다.

- 깊은 계층 구조를 가진 컴포넌트 트리에서 비효율적입니다. → Prop Drillin
Prop Drilling (프랍(프롭) 드릴링)
자식 컴포넌트는 부모 컴포넌트로부터 데이터를 전달 받기 위해 <script>에 props(프랍스, property, 프라퍼티)에 속성 명과 타입을 설정합니다.
부모 컴포넌트는 <template>에서 자식 HTML 태그 안에 넘겨줄 prop을 설정합니다.
RootComp.vue
<template>
<h1>Hello, Vue!</h1>
<FooterComp userID="testid" />
</template>
<script>
import FooterComp from './FooterComp.vue'
export default {
name : 'RootComp',
components : {
FooterComp
}
}
</script>
FooterComp.vue
<template>
<DeepChildComp :userID=useID />
</template>
<script>
import DeepChildComp from './DeepChildComp.vue'
export default {
name : 'FooterComp',
components : {
DeepChildComp
},
props: ['userID']
}
</script>
Footer에는 사용하지 않지만 자식 컴포넌트인 DeepChild가 사용하기 때문에 prop를 설정해야 합니다.
DeepChildComp.vue
<template>
<h2>{{ userID }}, Have a good time</h2>
</template>
<script>
export default {
name : 'DeepChildComp',
props: ['userID']
}
</script>
Provide(제공) / Inject(주입) 사용 ← Prop Drilling 해결
상위 컴포넌트는 하위 모든 컴포넌트에 대한 의존성 제공자 역할을 할 수 있습니다.
하위 모든 컴포넌트는 깊이에 관계없이 상위 체인의 컴포넌트에서 제공(provide)하는 의존성을 주입(inject)할 수 있습니다.

- 하위 모든 컴포넌트에 데이터를 제공하려면 provide() 함수를 사용
- 상위 컴포넌트에서 제공하는 데이터를 주입하려면 inject() 함수를 사용
하위 모든 컴포넌트에 데이터를 제공하기 위해서 provide() 함수 또는 provide 옵션을 사용합니다.
import { provide } from 'vue'
export default {
setup() {
provide('message', '안녕!')
}
}
상위 컴포넌트에서 제공하는 데이터를 주입하려면 inject() 함수 또는 inject 옵션을 사용합니다.
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return {
message
}
}
}
Composition API 대신 Options API로 하면 개발하면 다음과 같습니다.
export default {
provide: {
message: '안녕!'
}
}
export default {
inject: ['message'],
data() {
return {
fullMessage: this.message
}
}
}
Provide / Inject 사용
1. src\main.js에 provide(프로바이드, 제공) 함수를 추가합니다. → App-level Provide
import { createApp } from 'vue';
import { ref } from 'vue';
import App from './App.vue';
import router from './router';
const app = createApp(App);
app.provide('appTitle', '점심 메뉴 앱');
const greetingMessage = ref('즐거운 점심 시간되세요!');
const likeCount = ref(0);
function likeUp() {
this.likeCount++;
}
app.provide('useCommonStore', {
greetingMessage,
likeCount,
likeUp
});
app.use(router).mount('#app');
- Provide할 때 반응형 데이터와 상태 변경에 대한 함수가 같이 있는 것이 좋습니다.
- "use"로 시작해 "Store"로 끝나는 Store의 이름을 사용하는 것이 좋습니다.
2. src\views\LunchMenu\LunchMenuView.vue에 provide(프로바이드, 제공) 함수를 추가합니다. → Component Provide
<template>
<div class="lunch-menu">점심 메뉴</div>
<div class="lunch-view">
<router-view />
</div>
</template>
<script>
import { provide } from 'vue';
export default {
setup() {
provide('lunchmenuTitle', '점심 메뉴’);
}
}
</script>
3. src\views\LunchMenu\LunchMenuListView.vue에 Injext(인젝트, 주입) 함수를 추가하고 사용합니다.
<template>
<div>{{ appTitle }} - {{ lunchmenuTitle }} 리스트</div>
<div>
<span>{{ greetingMessage }} </span>
<button @click="likeUp">좋아요 - {{ likeCount }}</button>
</div>
:
</template>
<script>
:
import { inject } from 'vue';
export default {
setup() {
:
const appTitle = inject('appTitle');
const { greetingMessage, likeCount, likeUp } = inject('useCommonStore');
const lunchmenuTitle = inject('lunchmenuTitle');
:
return {
:
appTitle,
greetingMessage,
likeCount,
likeUp,
lunchmenuTitle
}
},
:
}
</script>
4. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/list)

"좋아요"버튼을 누르면 카운트가 증가합니다.
반응형 객체로 상태 관리
상태 관리
(https://ko.vuejs.org/guide/scaling-up/state-management.html)

1. src에 stores 디렉터리를 생성하고 useCountStore.js 파일을 생성합니다.

import { reactive } from 'vue';
export const useCountStore = reactive({
// 카운트
count: 0,
// 카운트를 증가시킵니다.
increment() {
this.count++;
},
// 카운트를 감소시킵니다.
decrement() {
this.count--;
},
// 카운트를 랜덤으로 증가시킵니다.
incrementByRandom() {
const random = Math.floor(Math.random() * 5);
this.count += random;
}
});
reactive()를 사용하여 반응형 객체를 만듭니다.
반응형 데이터와 상태 변경에 대한 함수가 같이 있는 것이 좋습니다.
2. src\views\LunchMenu\LunchMenuView.vue에 useCountStore을 추가하고 사용합니다.
<template>
<div class="lunch-menu">점심 메뉴
<button @click="countStore.incrementByRandom()">{{ countStore.count }}</button>
</div>
<div class="lunch-view">
<router-view />
</div>
</template>
<script>
import { provide } from 'vue';
import { useCountStore } from '@/stores/useCountStore.js'
export default {
setup() {
provide('lunchmenuTitle', '점심 메뉴');
const countStore = useCountStore;
return {
countStore
}
}
}
</script>
:
3. src\views\LunchMenu\LunchMenuListView.vue에 useCountStore을 추가하고 사용합니다.
<template>
<div>{{ appTitle }} - {{ lunchmenuTitle }} 리스트
<button @click="countStore.incrementByRandom()">{{ countStore.count }}</button>
</div>
:
</template>
<script>
:
import { useCountStore } from '@/stores/useCountStore.js'
export default {
setup() {
:
const countStore = useCountStore;
return {
:
countStore
}
},
:
}
</script>
4. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/list)

'Vue.js 3 & NodeJS > 사내교육 - 점심 메뉴' 카테고리의 다른 글
| [12] Frontend 개발 - 상태 관리, Login 관리, ID Token (0) | 2026.08.04 |
|---|---|
| [11] Frontend 개발 - 상태 관리, Store – Pinia (0) | 2026.08.04 |
| [9] Backend 개발 - 사용자 API 개발, 인증 처리, ID Token (0) | 2026.08.04 |
| [8] Backend 개발 - 사용자 API 개발, 인증 처리, Session + HTTP Cookie (0) | 2026.08.04 |
| [7] Frontend 개발 - 읽기 뷰 (ReadView), 수정, 삭제 생성 (0) | 2026.08.03 |