Vue 公式チュートリアル 〜 部品からデータを渡す
Vue 公式チュートリアルのステップ 13 は、「部品」の方から呼び出し元(親)にデータを渡す方法を学習します。
前回までのポイントは?
ステップ10までは、基本的に、 「Vue の部品」の基本的な記述の仕方を中心に学習しました。 ステップ11からは、メインのページから別に作成した「部品」を呼び出す方法を学習しています。記述の仕方は基本的に同じですが、ポイントは、「部品」を呼び出す側(親)と呼び出される側(子)の間でのデータのやり取りです。前回のステップ12では、呼び出し側から「部品」にデータを渡すやり方を学習しました。
呼び出し側と、呼び出される方の両方に記述が必要でした。
今回学ぶのは?
ステップ13では、前回とは反対に、呼び出される側(子)から、呼び出し側(親)にデータを渡す方法を学習します。
まずは、変更前のコードです。
(App.vue)
<script>
import ChildComp from "./ChildComp.vue";
export default {
components: {
ChildComp,
},
data() {
return {
childMsg: "No child msg yet",
};
},
};
</script>
<template>
<ChildComp />
<p>{{ childMsg }}</p>
</template>
これが、呼び出し元(親)のコードです。特に新しい点はありません。 「childMsg」という変数を作って、それを表示するようにしています。
これまでの、復習を兼ねてコードを見直してみてください。
つづいて、呼び出される側(子)の部品のコードです。
(ChildComp.vue)
<script>
export default {
emits: ["response"],
created() {
this.$emit("response", "hello from child");
},
};
</script>
<template>
<h2>Child component</h2>
</template>
このコードには、呼び出し側(親)にデータを渡すための記述が既に書かれています。 「export default {}」の中で、「emits:['response]」と「created() {}」の処理で、「this.$emit('response', 'hello from child')」が書かれています。
「emits:['response'」は、前回学習した、「props」に似た感じの変数です。「props」は、呼び出し元(親)から渡されるデータに対応する変数を各場所でしたが、「emits」は、呼び出し元(親)に渡すデータに対応する変数を書きます。 その上で、「this.$emit()」が親にデータを渡すための「書き方」になります。「this.$emit('response','hello from child')」の最初に部分に対応する変数名を書いて、その後に、渡すデータを書きます。
このコードでは、この部品が組み込まれて表示の準備ができた時に、データ「hello from child」が親に渡されるように書かれています。
この課題では、呼び出し元のコードを変更して、データを受け取る部分を書いて、「部品」(子)から受け取ったデータを表示するようにするのが課題です。
変更後のコードは?
変更後のコードは、呼び出し元(親)のみの変更になります。
(App.vue)
<script>
import ChildComp from "./ChildComp.vue";
export default {
components: {
ChildComp,
},
data() {
return {
childMsg: "No child msg yet",
};
},
};
</script>
<template>
<ChildComp @response="(msg) => (childMsg = msg)" />
<p>{{ childMsg }}</p>
</template>
変更点は:
<ChildComp @response="(msg) => childMsg = msg" />
です。これが呼び出した部品からデータを受け取る書き方です。 この書き方は、Javascript の「アロー関数」と呼ばれる書き方です。 この段階では、「このように書く」という覚え方で良いと思います。
この記述の意味は、「@response」は、「ボタンがクリックされたされた」のと似た「イベント」です。この場合は、呼び出した「部品」からデータが送られてきた場合の処理を書いています。送られて来たデータは、「msg」と仮に名前をつけた変数(アロー関数の引数)に入っていて、このデータをこの部品内の「chidMsg」に入れるという処理を書いています。今回は、シンプルな処理なので「chidMsg = msg」を直接書いていますが、メソッド(関数)を呼び出す事もできます。
呼び出す「部品」の記述は既に、データを渡す記述が書かれているので変更はありません。
(ChildComp.vue)
<script>
export default {
emits: ["response"],
created() {
this.$emit("response", "hello from child");
},
};
</script>
<template>
<h2>Child component</h2>
</template>
今回の応用は?
今回の課題では、表示の準備が整った際にデータを送るように書かれています。
このコードを少し変更して、部品側に「ボタン」を追加してボタンを押したら、変数を1づつ増やしてそのデータを呼び出し元(親)に渡すという記述に変えてみてください。全てこれまで学習したやり方で記述できるはずです。
変更例です
(App.vue)
<script>
import ChildComp from "./ChildComp.vue";
export default {
components: {
ChildComp,
},
data() {
return {
childMsg: "No child msg yet",
counter: 0,
};
},
methods: {
respond(msg) {
this.chldMsg = msg.msg;
this.counter = msg.counter;
},
},
};
</script>
<template>
<ChildComp @response="(msg) => respond(msg)" />
<p>{{ childMsg }}</p>
<p>{{ counter }}</p>
</template>
「部品」から渡されるデータを「JSON」の形にしています。
{
msg: "部品からのメッセージ",
counter: x # 部品の中のカウンターの値
}
で渡されるようにしています。 今回は、呼び出し元で受け取る際は、JSON ではなく、別々の変数に入れる事にしてメソッド(関数)で処理するようにしてみました。
methods:{
respond(msg) {
this.chldMsg = msg.msg;
this.counter = msg.counter;
}
}
表示は、
<template>
<ChildComp @response="(msg) => respond(msg)" />
<p>{{ childMsg }}</p>
<p>{{ counter }}</p>
</template>
のようにして、メッセージと、カウンタの値を表示しています。
部品の方です
(ChildComp.vue)
<script>
export default {
emits: ["response"],
data() {
return {
message: {
msg: "hello from child",
counter: 0,
},
};
},
created() {
this.$emit("response", this.message);
},
methods: {
clicked() {
this.message.counter++;
this.$emit("response", this.message);
},
},
};
</script>
<template>
<h2>Child component {{ message.counter }}</h2>
<button @click="clicked">+</button>
</template>
変数を JSON に変えています。
data(){
return {
message: {
msg: 'hello from child',
counter: 0
}
}
ボタンを HTML の部分に追加して、クリックされた時に、「clicked()」のメソッド(関数)を呼び出すようにしています。 部品側でも、カウンタの値を表示するようにしています。
<template>
<h2>Child component {{message.counter}}</h2>
<button @click="clicked">+</button>
</template>
呼び出した処理で、カウンタの値を1増やして、呼び出し元にデータを送っています。
methods: {
clicked() {
this.message.counter++;
this.$emit('response', this.message)
}
}
やり方は色々あると思いますので、自分なりにアレンジしてみてください。 今まで学習した内容をフル活用すると、色々できるようになっている事がわかるかと思います。
まとめ
今回のステップ13では、呼び出される部品(子)の方から呼び出した方(親)にデータを渡す方法を学習しました。 部品とのデータのやり取りができるようになると、色々な場面で利用できる共通の部品が作りやすくなります。 よく使う機能、表示を部品にすることで、Web 開発がより簡単で効率的にできるようになります。
今回の学習では、データのやり取り以外に「アロー関数」が出て来ています。 慣れないと覚えづらい書き方ですが、Javascript ではよく使われる書き方です。今回は、「このように書く」で良いかと思います。しかし、将来的には、きちんと学習してその仕組みを理解できると、自由に使いこなせるようになります。
同じような記述を「function()」(anonymous function/無名関数・匿名関数)を使って書くことも可能です。 「(a) => { a++ }」と「function(a) { a++ }」は同じ結果になります。この場合は、違いがありませんが、細かいところで違いがあるので、使い方によっては、結果が変わってくる場合もあります。アロー関数や無名関数の内側と外側で変数の有効な範囲などが微妙に違ってくるのがその原因になります。
今回の学習では、必要な事のみを学習する方法をとっていますので、こうした一部の詳細はあまり触れずに進めています。 将来的には、必要になる学習内容ですが、最初の段階で理解しようとするとそこで詰まってしまう場合が多いので、あまり気にせず、少し面倒なものは「書き方を覚える」という事にして先に進む方法にしています。 これが、Javascript を本格的に勉強する場合との大きな違いです。
今は、ちょっと難しくても、実際に書いて「どんな結果になるか」を見て認識しておくと、将来詳細を勉強する際に理解する大きな助けになります。
難しい事は「将来必要になったら学習する」で今は問題ありません。余り気にせずに先に進みましょう!
次回は、2022 年 3 月 14 日にお届けします。お楽しみに!