実行環境
macOS Catalina バージョン 10.15.7
MacBook Pro 13インチ
Vue 2.6.12
はじめに
vue.jsの勉強を始めたのですが、そのメモ残しということでQiitaに投稿することにしました。間違いがあれば指摘お願いします。今回はコンポーネントについて学んだことをまとめます。
コンポーネント内のdataは関数型である必要がある
コンポーネント内で定義されているdataは関数型である必要があります。その理由として主なのは関数型にしないとデータが一つのメモリで共有されてしまうからです。関数型にすることによって、vueインスタンスが各々でデータを保持することができるようになります。具体例を挙げて見てみましょう。
<template>
<div>
<p>{{ number }}</p>
<button @click="number++">+1</button>
</div>
</template>
<script>
export default {
data: function() {
return {
number: 0,
}
}
}
</script>
<template>
<div>
<CountUp></CountUp>
<CountUp></CountUp>
<CountUp></CountUp>
</div>
</template>
<script>
import CountUp from './components/ CountUp'
export default {
components: {
CountUp,
}
}
</script>
コンポーネント内でdataを関数型で定義していることによって、各々のvueインスタンスが別々の値を保持していることがわかります。しかし、これが関数型でなかったらどうなるでしょうか?
<template>
<div>
<p>{{ number }}</p>
<button @click="number++">+1</button>
</div>
</template>
<script>
var countNumber = {
number: 0
}
export default {
data: function() {
return countNumber
}
}
</script>
App.vueの内容はそのままでCountUp.vueの内容を上のように書き直してみます。すると、以下の画像のように全てのvueインスタンスでデータが共有されて、三つのうち一つのボタンを押すと、全ての数字が更新されていることに気がつくはずです。
データが一つのメモリで共有されることによって、同時に複数のvueインスタンスのデータが更新されるという結果になりました。これがコンポーネント内ではデータは関数型で定義する必要がある理由です。
ローカル登録とグローバル登録
先程のコード(App.vue, CountUp.vue)をみてみると、コンポーネントをローカル登録して使用していることがわかります。ローカル登録とはあるコンポーネントをインポートしたファイルでしか使用できないような登録の方法です。先ほどはApp.vueの子コンポーネントとしてCountUp.vueを登録しましたがこのCountUpコンポーネントはローカル登録のためApp.vueでしか使用できません。
親子間のデータの受け渡し
親→子のデータ授受
親コンポーネントであるApp.vueから子コンポーネントであるCountUp.vueにデータを送り、表示してみましょう。先程のコードを使います。
<template>
<div>
<!-- 子コンポーネントへのデータのおくり口を作る -->
<CountUp :num="number"></CountUp>
<CountUp :num="number"></CountUp>
<CountUp :num="number"></CountUp>
</div>
</template>
<script>
import CountUp from './components/ CountUp'
export default {
// 親コンポーネントでデータを定義
data: function(){
number: 0,
}
components: {
CountUp,
}
}
</script>
<template>
<div>
<p>{{ num }}</p>
<button @click="num++">+1</button>
</div>
</template>
<script>
export default {
// 子コンポーネントでデータの受け皿を作る
props: ["num"]
}
</script>
上記のコードのように、
①親コンポーネントでおくりたいデータを定義する
②親コンポーネント中の子コンポーネントタグ内にデータのおくり口を作る
③子コンポーネントでデータの受け口を作る
の三つの手順を踏むことで簡単に親から子にデータを送ることが出来ます。
子→親へのデータの授受
<template>
<div>
<!-- 子コンポーネントの方から発火されるイベントの作成 -->
<CountUp :number="number" @addition="addition"></CountUp>
<p>{{ addNum }}</p>
</div>
</template>
<script>
import CountUp from './components/ CountUp'
export default {
data: function() {
return {
number: 0,
addNum: 0,
}
},
methods: {
// 子コンポーネントの方から発火されるイベントによって実行されるメソッドの定義
addition(value) {
this.addNum = value;
}
},
components: {
CountUp,
}
}
</script>
<template>
<div>
<h2>いいね</h2>
<p>{{ num }}</p>
<button @click="num++">+1</button>
<!-- クリックイベントの作成 -->
<button @click="addition">+2</button>
</div>
</template>
<script>
export default {
props: ["number"],
data: function() {
return {
num: this.number,
addNum: 0
}
},
methods: {
addition() {
this.addNum += 2
// 親コンポーネントのイベントを発火
this.$emit("addition", this.addNum);
}
}
}
</script>
これで子から親にデータを渡すことが出来ます。大まかな手順は以下の通りです。
-
子コンポーネントでイベントの作成
今回はクリックイベントを作成しましたが、別にイベントならなんでもいいです。 -
子コンポーネントの方から親コンポーネントのイベントを発火
this.$emit("イベント名", 渡したいデータ)をすると、親コンポーネントのイベントを子コンポーネントから発火することが出来ます。 -
親コンポーネントでイベントの作成
手順2で指定した親コンポーネントのイベントを作成します。 -
子コンポーネントから発火される親コンポーネントのイベントによって実行されるメソッドの定義
手順3で定義したイベントによって実行されるメソッドを定義します。
+1ボタンを押すと、親コンポーネントで定義されたnumberが子に渡され、子コンポーネントで表示されている数字が+1される。
+2ボタンを押すと、子コンポーネントで定義されたaddNumが親に渡され、親コンポーネントで表示されている数字が+2される。
さいごに
ここまでコンポーネント関連の重要事項をまとめてきました。このことを伝えたいならこんな感じのコードの方がいいよ!!というようなことであったり、間違っているところがあれば是非指摘をいただきたいのでよろしくお願いします。