컴포넌트의 provide
, inject
두 개의 키워드에 대해 살펴보도록 합시다. 더욱 자세한 사항은 공식 문서를 참고해주시기 바랍니다.
일반적으로 데이터를 부모에서 자식 컴포넌트로 전달해야할 때 props
를 사용합니다. 특정한 두 컴포넌트 사이에 깊이 중첩된 컴포넌트가 있는 구조의 경우 하위 컴포넌트에서 상위 컴포넌트의 무언가가 필요한 경우를 상상해보십시오. 이 경우에 두 컴포넌트 사이의 모든 컴포넌트에 prop
를 전달해야하므로 굉장히 번거로울 것입니다.
이러한 경우 provide
와 inject
쌍을 사용할 수 있습니다. 부모 컴포넌트는 컴포넌트 계층 구조의 깊이와 상관없이 모든 자식에 대한 종속성 제공자 역할을 할 수 있습니다. 이 기능은 2개의 부분으로 구성됩니다: 부모 컴포넌트는 데이터 제공을 위해 provide
옵션을 사용하며, 자식 요소는 데이터 사용을 위해 inject
옵션을 사용합니다.
Vue의 공식 문서에 작성된 내용이며, 이에 대해서 좀 더 쉽게 알아보도록 할까요?
App.vue(조상[상위] 컴포넌트)
<Parent :msg="message" />
import Parent from '~/components/Parent' export default { components: { Parent }, data() { return { message: 'Hello world!' } } }
Parent.vue(부모 컴포넌트)
<Child :msg="msg" />
import Child from '~/components/Child' export default { components: { Child }, props: { msg: { type: String, default: '' } } }
Child.vue(자식 컴포넌트)
<div> {{ msg }} </div>
export default { props: { msg: { type: String, default: '' } } }
아래의 예시처럼 손자 컴포넌트인 msg
를 루트 컴포넌트에 전달하려고 하면 두 단계를 거쳐야만 하고, 중간에 있는 Parent.vue
파일의 props
는 사용하지도 않지만 msg
라는 데이터를 Child.vue
에 전달하는 역할말고는 전혀 사용을 하고 있지 않습니다.
이러한 부분을 해결하기 위한 것이 provide
와 inject
키워드인 것입니다.
App.vue(조상[상위] 컴포넌트)
<Parent />
import Parent from '~/components/Parent' export default { components: { Parent }, data() { return { message: 'Hello world!' } }, provide() { return { msg: this.message // data()의 message 사용할게! } } }
위처럼 data()
의 message
옵션 부분을 provide
의 msg
라는 이름으로 사용하겠다는 코드를 작성해줍니다. 그렇다면, Parent.vue
를 중간 매개체로 사용하지 않아도 되겠죠? 그러므로 html 부분에서는 <Parent />
코드만 작성해주시면 됩니다.
Parent.vue(부모 컴포넌트)
<Child /> // :msg="msg" 부분 삭제
import Child from '~/components/Child' export default { components: { Child } }
Child.vue(자식 컴포넌트)
<div> {{ msg }} </div>
export default { inject: ['msg'] }
위와 같이 데이터를 받을 Child.vue
에 inject
라는 키워드를 사용하여 배열 데이터 안에 provide
라는 옵션을 통해서 지정한 이름인 msg
를 명시해줍니다. 그러면, msg
가 하나의 데이터로 취급이 되어 {{ msg }}
이 부분에서 데이터가 출력되게 만들어줄 수 있습니다.
이렇게 provide
, inject
라는 키워드를 사용하면 중간 과정 없이 바로 데이터를 전달해줄 수 있습니다. 그러나 여기서 주의사항이 있습니다.
그것은 바로 provide
키워드는 기본적으로 반응성을 제공할 수 없다는 것입니다. 그렇기 때문에 provide
는 데이터를 전달해서 출력하는 용도로만 사용하거나 혹은 추가 작업이 필요합니다.
App.vue(조상[상위] 컴포넌트)
<button @click="message = 'Good?'"> Click! </button> <h1>App: {{ message }}</h1> <Parent />
import Parent from '~/components/Parent' import { computed } from 'vue' // computed 가져오기 export default { components: { Parent }, data() { return { message: 'Hello world!' } }, provide() { return { msg: computed(() => { return this.message // 콜백 함수 형태로 return }) // msg: computed(() => this.message) // 중괄호, return 생략 가능 } } }
Child.vue(자식 컴포넌트)
<div> {{ msg.value }} </div> // msg라는 데이터의 value 속성 값
export default { inject: ['msg'] }
이처럼 msg
라는 provide
에서 넘어온 데이터는 계산된 하나의 객체 데이터이며, 그 객체 데이터에서 내가 원하는 데이터를 출력하기 위해서는 그 안의 value라는 속성을 사용해야 합니다.
이렇게 provide
키워드를 사용하여 반응성을 유지하는 데이터를 만들기 위해서는 computed
라는 함수를 실행해서 그 내부에서 반응성을 갖고 싶은 데이터를 반환해주면 되는 것입니다.