Last Updated: 2021-02-08

vuejs-provide-inject-cover

vue.js에서 provide/inject api는 보통 많이 사용하지는 않는다. 핵심적인 요소 간주하기에는 무언가 부족하기 때문이기도 하며, Vue.js 공식 문서에서 provide/inject는 일반 애플리케이션 코드에 사용하지 않는 것이 좋다고 명시되어있기 때문이다. 하지만 모르는 것보다 아는 것이 이득이며 때로는 이 provide/inject가 도움이 되기 때문에 이번 포스팅에서 언급하였으며, 몇 가지 얘기해 보려 한다.

여기서 provide/inject 개념을 이해하고 예제를 통하여 완벽하게 파악해보도록 하자.

provide/inject

provide/inject 개념은 vue 2.2.0부터 추가된 기능이다. 기능치고는 가이드에 사용법 또는 왜 사용하는지와 왜 일반 애플리케이션 코드에서 사용하지 않는 것이 좋은지에 대한 정확한 정보를 찾기 힘들다.

provide/inject는 말 그대로 해석하는 편이 이해가 빠르다. provide제공이며, inject주입이다. 이를 먼저 기억하고 글을 읽어 나가도록 하자.

provide/inject의 개념은 컴포넌트의 계층구조에서 빛을 발한다.
보통 프로젝트나 vue를 사용하게 되면 컴포넌트의 깊이 있는 계층 구조가 되는 경우가 허다하다. 특정 기능을 컴포넌트 단위로 쪼개고 이를 각 vue page 개념의 컴포넌트에서 사용할 때 컴포넌트 안에 컴포넌트가.. 그리고 또 그 안의 컴포넌트가 존재하는 때도 있는데 이런 경우 우리는 보통 가장 기본적인 형태인 props를 하위 컴포넌트로 전달하여 사용하는 경우가 많다.

이런 경우 컴포넌트의 깊이에 따라 가상 최상위 컴포넌트부터 가장 최하위 컴포넌트까지 props를 전달하기엔 비효율적으로 느낄 것이다. 이런 경우에 바로 provide/inject 개념을 사용한다.

컴포넌트 계층 구조의 이해

위에서 설명한 컴포넌트 계층 구조를 좀 더 명확하게 잡고 가자.

계층 구조에서 props를 전달하는 것은 매우 현명한 방법이다. 비록 코드상 비효율적이거나 코드 추적이 불편한 점이 있을 테지만 가장 vue component 개념에 적합한 방법이다. 때로는 이런 내용이 코드 추적 간 중간 단계의 컴포넌트까지 파헤쳐야 하기 때문에 코드 추적이 명확하다고 볼 수 있다.

vue-component-props-flow

provide/inject의 사용 시기

그럼 컴포넌트 계층 구조에서 props를 통한 방법이 가장 최적이라면 언제 provide/inject를 사용해야 하는 걸까? 이 질문은 처음에 말한 Vue 공식 문서에 나와 있다.

provide/inject는 주로 고급 플러그인 또는 컴포넌트 라이브러리에서 사용됩니다. 일반 애플리케이션에서 사용하지 않는 것이 좋습니다.

결론부터 말하면, 사실 플러그인 또는 컴포넌트와 일반 애플리케이션에서 사용해도 된다. 하지만 일반 애플리케이션에서 사용하지 않는 것이 좋다는 것은 provide/inject를 사용하면 할수록 코드의 추적이 어렵기 때문이다.

vue-component-provide-inject

컴포넌트의 계층적인 구조에서 props가 최적의 방법이라는 건 그만큼 컴포넌트의 추적이 가능하기 때문인데 이 provide/inject를 사용한다면 계층적인 구조에서 중간 단계 컴포넌트를 건너뛰기 때문이다. 이에 반면 보통 플러그인이나 컴포넌트는 단일 모듈 형태로 되어있으며 깊은 계층구조를 가지지 않고 일반 애플리케이션보다 복잡한 구조를 가지지 않기 때문에 제공된다.

물론, 플러그인이나 컴포넌트의 구조가 복잡하다면 provide/inject의 사용은 지양해야 할 것이다.

provide/inject 사용 방법

위에서 provide제공이라고 하였고, inject주입이라고 하였다. provide는 부모 컴포넌트에서 props제공하는 것이고 ,inject는 하위 컴포넌트에서 제공된 props주입하여 사용한다.

provide-inject-use

위 그림을 보면 부모 컴포넌트에서 provide를 정의한다. 그리고 그 하위의 모든 컴포넌트는 inject를 통해 정의된 provide를 사용 할 수 있다.

이제 예를 통해서 알아보도록 하자.

프로젝트 생성은 Vue-CLI를 통하여 생성하도록 하겠다. Vue-CLI에 대한 자세한 내용은 [Vue.JS] Vue-CLI 3 시작하기를 참고하도록 하자.

vue create vue-provide-inject

이제 App.vue를 수정하고 components 경로에 세개의 컴포넌트를 만들고 아래와 같이 작성하자.

App.vue

<template>
<div id="app" class="comp">
<p class="comp-name">App</p>

<span class="inject-text">provide :
<span class="inject-value">'inject props'</span>
</span>

<first name="first"/>
</div>
</template>

<script>
import First from '@/components/First'

export default {
name: 'App',
components: {
First
},
provide () {
return {
injectProps: 'inject value'
}
}
}
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}

.comp {
text-align: left;
border: 1px solid #444444;
padding: 30px;
}

.comp.comp-fcolor {
background: #f5acac96;
}

.comp.comp-scolor {
background: #0000ff30;
}

.comp.comp-tcolor {
background: #ffff0052;
}

.comp-name {
color: #0020f8
}
</style>

First.vue

<template>
<div class="comp comp-fcolor">
<p class="comp-name">First Component</p>
<p>props : {{ name }}</p>

<second :name="name"/>
</div>
</template>

<script>
import Second from '@/components/Second'

export default {
name: 'first',
components: { Second },
props: {
name: String
}
}
</script>

Second.vue

<template>
<div class="comp comp-scolor">
<p class="comp-name">Second Component</p>
<p>props : {{ name }}</p>

<third :name="name"/>
</div>
</template>

<script>
import Third from '@/components/Third'

export default {
name: 'second',
components: { Third },
props: {
name: String
}
}
</script>

Third.vue

<template>
<div class="comp comp-tcolor">
<p class="comp-name">Third Component</p>
<p>props : {{ name }}</p>

<span class="inject-text">inject props :
<span class="inject-value">{{ injectProps }}</span>
</span>
</div>
</template>

<script>
export default {
name: 'third',
props: {
name: String
},
inject: ['injectProps']
}
</script>

<style>
.inject-text {
font-weight: bold;
}

.inject-value {
color: red
}
</style>

먼저 결과를 확인해보자.

provide-inject-result

위 내용을 보면 First Component에서 Second Component를 자식으로 가지고 Second Component에서는 Third Component를 자식으로 가지는 계층 구조이다.

기존처럼 props를 통해 App.vue부터 시작하여 가장 하위 컴포넌트인 Third Component까지 전달하면서 화면에 출력하고 있다. 이는 props를 하위까지 전달하기 때문에 결과적으로 세 컴포넌트의 props는 같을 것이다. 그리고 같은 상황에서 App.vue부터 Third Component까지 provide/inject를 사용하여 결과를 전달하고 있다.

최초 App.vue에서 provide를 통하여 injectProps를 제공하였다. 그리고 마지막 컴포넌트인 Third Component에서 inject를 통하여 injectProps를 주입하고 출력하였다. 이러한 상황에서 동일하게 props와 같은 결과를 전달하는 경우와 비교를 해보자면 Root 컴포넌트에서 가장 하위의 컴포넌트까지 단번에 props를 전달한 결과가 된다.


이처럼 어느 상황 속에서는 한번에 props를 전달하는 결과이니 마냥 편할 수도 있지만 복잡한 애플리케이션에서는 이런 이유로 인하여 소스 코드 추적이 어려워 지기 때문에 조심해서 사용할 필요가 있다.
이 외에 provide/inject에 대한 자세한 설명은 Vue.js 공식 문서에서 확인해 보도록 하자.