
[Vue 3] Composition API - Provide와 Inject
이미 이전 글을 통해 Provide와 inject에 대해 다루었지만, Composition API에서는 어떻게 사용하는지는 보지 않았습니다. 그래서 다시금 내용을 복습하고 Composition API에서의 provide와 inject에 대해서 알아보겠습니다.
provide / inject 필요성
컴포넌트 간의 통신은 props와 emits을 통해 이루어집니다. 그런데 만약 이러한 계층 구조가 깊어지면 깊어질수록 상위의 컴포넌트가 깊은 하위 컴포넌트에게 원하는 데이터를 전달하기 위해서 여러 번의 props를 사용해야합니다. 반대로 이벤트를 emit할 때도 마찬가지입니다.
그래서 이를 한 번에 전달하기 쉽도록 vue에서는 provide와 inject 기능을 제공합니다.

provide는 상위 컴포넌트에서 전달하고자 하는 값을, inject에서는 상위 컴포넌트에서 받고자 하는 값을 정의하면 됩니다.
provide
provide
함수를 import 한 다음 첫 번째 매개변수에 키 값을, 두 번째 매개변수에 값을 넣어주면 됩니다.
<script>
import { provide } from 'vue'
export default {
setup() {
provide(/* 키 */ 'message', /* 값 */ '안녕!')
}
}
</script>
setup script에서도 크게 다르지 않습니다.
<script setup>
import { provide } from 'vue';
provide(키, 값);
</script>
여기서 키 값은 문자열 또는 Symbol
을 넣어서 사용할 수 있으며, 값은 어떤 타입이여도 상관없습니다.
앱에서 provide
상위 컴포넌트가 아니라 앱 수준의 최상단에서 provide를 원하는 경우 app의 provide 함수를 사용하면 됩니다.
import { createApp } from 'vue';
const app = createApp({});
app.provide(키, 값);
Inject
inject
함수를 import 한 다음 provide
에서 받고자 하는 키 값을 동일하게 사용하면 됩니다. 두 번째 매개변수는 기본값으로 만약 해당 키 값이 provide를 통해 전달되고 있지 않다면 이 값을 반환합니다. 기본값은 선택사항으로 키 값만 넣어도 됩니다.
<script>
import { inject } from 'vue';
export default {
setup() {
const value = inject(키값, 기본값);
return { value };
}
}
</script>
script setup에서도 동일합니다.
<script setup>
import { inject } from 'vue';
const message = inject(키 값, 기본값);
</script>
inject에서 값을 변화시키고 싶다면
provide로 제공받은 값을 inject하는 컴포넌트에서 변화시키고 싶을 수 있습니다. 하지만 값을 변경시키는 작업은 emits처럼 상위 컴포넌트에서 해주는 것이 유지보수에 좋습니다.
따라서 값을 변경시키는 작업은 provide를 제공하는 컴포넌트에서 함수로 만들어주고, 이 함수를 inject하는 컴포넌트에 전달하면 됩니다.
<script setup>
import MyComponent from "./components/MyComponent.vue";
import { provide, ref } from "vue";
const name = ref("vuelogger");
// 업데이트 해주는 함수
function update(newName) {
name.value = newName;
}
provide("name", {
name,
update,
});
</script>
<template>
<MyComponent />
</template>
<script setup>
import { inject } from "vue";
const { name, update } = inject("name");
</script>
<template>
<button @click="update('famous man')">{{ name }}</button>
</template>
사실 위 함수를 사용할 필요없이 하위 컴포넌트에서 직접 바꿀 수도 있습니다.
<button @click="name = 'Iron man'">{{ name }}</button>
하지만 위에서도 언급했듯이 provide로 제공한 값이 어느 컴포넌트에서 변화시켰는지 찾기 어려워질 수 있기 때문에, 업데이트 해주는 함수를 따로 제공받아서 사용해야합니다. 만일 이렇게 전달받은 값을 변화시키지 못하도록 막고 싶다면 readonly
를 사용하면 됩니다.
<script setup>
import MyComponent from "./components/MyComponent.vue";
import { provide, ref, readonly } from "vue";
const name = ref("vuelogger");
const readonlyName = readonly(name);
// 업데이트해주는 함수
function update(newName) {
name.value = newName;
}
provide("name", {
name: readonlyName,
update,
});
</script>
<template>
<MyComponent />
</template>
만일 하위 컴포넌트에서 직접 바꾸려하면 다음과 같은 경고가 나타나면서 바뀌지 않습니다.

중복 방지를 위한 Symbol
provide를 한 사람이 아닌 여러 사람이 만든다면 동일한 이름의 provide 키를 쓸 가능성이 생깁니다. 그래서 이러한 중복을 막기위해 Symbol
을 사용해야합니다.
export const myInjectionKey = Symbol()
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* 제공할 데이터 */
})
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)