Vue Provide / Inject
Vue の Provide / Inject は、あるコンポーネントから他のコンポーネントへデータを配信するために使用されます。これは特にコンポーネント階層が深くなる大規模なプロジェクトで非常に有用です。
- Provide(プロバイド): データを他のコンポーネントから利用可能な状態(公開)にします。
- Inject(インジェクト): 公開されたデータを受け取って使用します。
Provide / Inject は、コンポーネント間でデータを共有する際、props(プロップス)を使用する代わりの強力な手段となります。
1. Provide / Inject の仕組み
コンポーネントの中にさらにコンポーネントが入っているような大規模プロジェクトでは、App.vue から深い階層にあるサブコンポーネントへ props でデータを渡すのは困難です。なぜなら、データが通過するすべての中間コンポーネントで props を定義しなければならないからです(これを「プロップ・ドリリング」や「バケツリレー」と呼びます)。
props の代わりに Provide / Inject を使用すれば、データを「提供(Provide)」する場所と、データを「注入(Inject)」する場所だけで定義を完結させることができます。
2. データの提供 (Provide)
データを他のコンポーネントから利用可能にするには、provide オプションを使用します。
2.1 実装例 (App.vue)
以下のコードでは、foods 配列を provide することで、プロジェクト内の他のどのコンポーネントからでもインジェクト(注入)して利用できる状態にしています。
App.vue:
<template>
<h1>食べ物リスト</h1>
<div @click="this.activeComp = 'food-about'" class="divBtn">概要</div>
<div @click="this.activeComp = 'food-kinds'" class="divBtn">種類</div>
<div id="divComp">
<component :is="activeComp"></component>
</div>
</template>
<script>
export default {
data() {
return {
activeComp: 'food-about',
// このデータを配信したい
foods: [
{ name: 'ピザ', imgUrl: '/img_pizza.svg' },
{ name: 'リンゴ', imgUrl: '/img_apple.svg' },
{ name: 'ケーキ', imgUrl: '/img_cake.svg' },
{ name: '魚', imgUrl: '/img_fish.svg' },
{ name: 'ご飯', imgUrl: '/img_rice.svg' }
]
}
},
provide() {
return {
// foods 配列を外部に公開
foods: this.foods
}
}
}
</script>3. データの注入 (Inject)
App.vue で foods 配列が provide されたので、これを FoodKinds コンポーネントで受け取ることができます。
FoodKinds コンポーネントに foods データをインジェクトすることで、App.vue にある元のデータを使用して、さまざまな食べ物を表示することが可能になります。
3.1 実装例 (FoodKinds.vue)
FoodKinds.vue:
<template>
<h2>さまざまな食べ物の種類</h2>
<p><mark>このアプリケーションでは、食べ物データは "App.vue" で提供(Provide)され、この "FoodKinds.vue" コンポーネントで注入(Inject)されて表示されています:</mark></p>
<div v-for="x in foods" :key="x.name">
<img :src="x.imgUrl">
<p class="pName">{{ x.name }}</p>
</div>
</template>
<script>
export default {
// 公開されている 'foods' を取得
inject: ['foods']
}
</script>
<style scoped>
div {
margin: 10px;
padding: 10px;
display: inline-block;
width: 80px;
background-color: #28e49f47;
border-radius: 10px;
}
.pName {
text-align: center;
}
img {
width: 100%;
}
</style>