Vue.jsでは、通常、親コンポーネントから子コンポーネントにデータを渡す時にはpropsを使います。
1 2 3 |
<div id="app"> <child v-bind:message="message"></child> </div> |
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リストのユーザー名を親アプリケーションから孫コンポーネントに渡します。
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') |
1 2 3 |
<div id="app"> <todo-list v-bind:items="todos"></todo-list> </div> |
上記の例では、親コンポーネント(アプリケーション)でprovideを使用して「firstName」と「lastName」を定義しています。
孫コンポーネントの「TodoItem」では、それを受け取るためにjnjectでprovideに対応する「firstName」と「lastName」を定義しています。
サンプルコードの実行結果
上記のコードをブラウザーで実行すると、以下のような画面が表示されます。
ルートの親コンポーネント(アプリケーション)から、2階層下にあたる孫コンポーネントにデータが引き渡されて、ユーザー名が表示されているのが確認できます。