
Vue.jsでは、通常、親コンポーネントから子コンポーネントにデータを渡す時にはpropsを使います。
HTML
| 1 2 3 | <div id="app">   <child v-bind:message="message"></child> </div> | 
JavaScript
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Vue.createApp({   components: {     'child': {       template: '<div>{{message}}</div>',       props: {         message: String       } 	}   },   data: function() {     return {       message: 'Hello Vue.js!'     }   } }).mount('#app') | 
上記の親子コンポーネントでは、propsのmessageで親から子へデータを渡しています。
propsでは親から子にデータを渡すことはできますが、複数の階層に連なっているコンポーネント(親→子→孫…)の場合、深い階層にあるコンポーネントに対して親から直接データを渡すことはできません。
親、子、孫、ひ孫の4階層を持つ構成になっている場合、propsを使って親からひ孫のコンポーネントにデータを渡したい場合は、「親から子に渡し、子から孫に渡し、孫からひ孫に渡す」といった風に、鎖のようにつながったコンポーネント全体にpropsを定義してデータを渡す必要があります。
これは、コードとしては冗長であるかもしれません。
そこでVue.jsには、深くネストされたコンポーネントにデータを渡す仕組みとして「provide / inject」という仕組みが用意されています。
ここでは、データを渡す側に定義するprovideと、データを受け取る側に定義するinjectについて紹介します。
ネストされたコンポーネント
本記事では、provide / injectの説明のために、以下の構造のコンポーネントを使用します。
| 1 2 3 | Root └─ TodoList    └─ TodoItem | 
provide / inject
provideとinjectを利用するとコンポーネント階層の深さに関係なく、親コンポーネントはすべての子孫コンポーネントへデータを渡すことができます。
ルートとなる親コンポーネントから子孫コンポーネントにデータを渡す際は、親コンポーネントにprovideを定義し、子孫コンポーネントにinjectを定義します。
サンプルコード
以下にprovideとinjectを使用する例を示します。
ここでは、Todoリストのユーザー名を親アプリケーションから孫コンポーネントに渡します。
JavaScript
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // Root const app = Vue.createApp({   data() {     return {       todos: [ 	    '犬の散歩', 		'掃除', 		'洗濯' 	  ]     }   },   provide: {     firstName: '太郎',     lastName: '田中'   }, }) // TodoList app.component('todo-list', {   template: `     <div>       件数: {{items.length}}     </div>     <ul>       <todo-item v-for="item in items" 	             v-bind:item="item"></todo-item>     </ul>   `,   props: {     items: Array   } }) // TodoItem app.component('todo-item', {   template: '<li>{{item}} / {{text}}</li>',   props: {     item: String   },   inject: ['firstName', 'lastName'],   computed: {     text: function() {       return `${this.lastName} ${this.firstName}`     }   } }) // マウント app.mount('#app') | 
HTML
| 1 2 3 | <div id="app">   <todo-list v-bind:items="todos"></todo-list> </div> | 
上記の例では、親コンポーネント(アプリケーション)でprovideを使用して「firstName」と「lastName」を定義しています。
孫コンポーネントの「TodoItem」では、それを受け取るためにjnjectでprovideに対応する「firstName」と「lastName」を定義しています。
サンプルコードの実行結果
上記のコードをブラウザーで実行すると、以下のような画面が表示されます。

ルートの親コンポーネント(アプリケーション)から、2階層下にあたる孫コンポーネントにデータが引き渡されて、ユーザー名が表示されているのが確認できます。
