Vue Props
1. コンポーネントへのデータ渡過
Props(プロップス) は、Vue の設定オプションの一つです。Props を使用すると、コンポーネントタグにカスタム属性を追加することで、コンポーネントへデータを渡すことができます。
前ページでは、3つのコンポーネントすべてに「Apples(リンゴ)」と表示される例を確認しました。Props を使用すれば、各コンポーネントに異なるデータを流し込み、それぞれ異なる内容を表示させることが可能になります。
まずは、「リンゴ」「ピザ」「ライス」を表示するシンプルなページを作成してみましょう。
メインのアプリケーションファイルである App.vue で、<food-item/> コンポーネントタグに独自の属性 food-name を作成し、データを渡します。
App.vue:
<template>
<h1>食べ物</h1>
<food-item food-name="リンゴ"/>
<food-item food-name="ピザ"/>
<food-item food-name="ライス"/>
</template>
<script></script>
<style>
#app > div {
border: dashed black 1px;
display: inline-block;
width: 120px;
margin: 10px;
padding: 10px;
background-color: lightgreen;
}
</style>2. コンポーネント内部でのデータ受信
App.vue から food-name 属性を通じて送られたデータを受信するには、props 設定オプションを使用します。受信する属性をリストアップすることで、コンポーネントファイルがそれらを認識し、データプロパティ と同じようにどこでも使用できるようになります。
FoodItem.vue:
<script>
export default {
props: [
'foodName'
]
}
</script>ここで重要なルールがあります。<template> タグ内では、属性名は単語をダッシュで区切る ケバブケース(kebab-case) で記述しますが、JavaScript ではハイフンは使用できません。そのため、JavaScript 側では キャメルケース(camelCase) で記述する必要があります。Vue はこれを自動的に関連付けて理解してくれます。
最終的に、「リンゴ」「ピザ」「ライス」を表示する <div> 要素の例は以下のようになります。
2.1 実装例:基本的な Props の受け渡し
App.vue:
<template>
<h1>食べ物</h1>
<food-item food-name="リンゴ"/>
<food-item food-name="ピザ"/>
<food-item food-name="ライス"/>
</template>FoodItem.vue:
<template>
<div>
<h2>{{ foodName }}</h2>
</div>
</template>
<script>
export default {
props: [
'foodName'
]
}
</script>
<style></style>3. さまざまデータ型の受け渡しとレイアウト拡張
次に、各食べ物の「説明文」を追加し、これらの要素を Flexbox ラッパーで囲むようにコードを拡張してみましょう。
3.1 実装例:複数 Props とレイアウト
App.vue:
<template>
<h1>食べ物</h1>
<div id="wrapper">
<food-item
food-name="リンゴ"
food-desc="リンゴは木に実る果物の一種です。"/>
<food-item
food-name="ピザ"
food-desc="ピザはパン生地をベースに、トマトソース、チーズ、トッピングを乗せたものです。"/>
<food-item
food-name="ライス"
food-desc="ライスは多くの人々に愛されている穀物の一種です。"/>
</div>
</template>
<script></script>
<style>
#wrapper {
display: flex;
flex-wrap: wrap;
}
#wrapper > div {
border: dashed black 1px;
margin: 10px;
padding: 10px;
background-color: lightgreen;
}
</style>FoodItem.vue:
<template>
<div>
<h2>{{ foodName }}</h2>
<p>{{ foodDesc }}</p>
</div>
</template>
<script>
export default {
props: [
'foodName',
'foodDesc'
]
}
</script>
<style></style>4. ブーリアン型の Props
Props にはさまざまなデータ型を渡すことができ、コンポーネント作成時のルールを定義できます。
新しく isFavorite という Props を追加してみましょう。これは true または false を持つ ブーリアン(Boolean) 型とし、お気に入りの場合にのみ v-show を使ってお気に入りマークの <img> を表示するために使用します。
文字列以外のデータ型 を Props として渡すには、属性名の前に v-bind:(または省略形の :)を記述する必要があります。
App.vue:
<template>
<h1>食べ物</h1>
<p>お気に入りの食べ物には「修了証」の画像が表示されます。</p>
<div id="wrapper">
<food-item
food-name="リンゴ"
food-desc="リンゴは木に実る果物の一種です。"
v-bind:is-favorite="true"/>
<food-item
food-name="ピザ"
food-desc="ピザはパン生地をベースに、トマトソース、チーズ、トッピングを乗せたものです。"
v-bind:is-favorite="false"/>
<food-item
food-name="ライス"
food-desc="ライスは多くの人々に愛されている穀物の一種です。"
v-bind:is-favorite="false"/>
</div>
</template>4.1 実装例:ブーリアン値による条件付き表示
FoodItem.vue:
<template>
<div>
<h2>
{{ foodName }}
<img src="/img_quality.svg" v-show="isFavorite">
</h2>
<p>{{ foodDesc }}</p>
</div>
</template>
<script>
export default {
props: ['foodName', 'foodDesc', 'isFavorite']
}
</script>
<style>
img {
height: 1.5em;
float: right;
}
</style>5. Props インターフェース
これまでの例では、isFavorite が確実に受け取れているか、それが本当にブーリアン型であるかを確証する方法がありませんでした。これを解決するために、受信する Props の データ型(Type) を定義し、必須(Required) 設定や、独自な バリデーション関数 を設定することができます。
Props の定義を詳細に記述することは、チーム開発におけるドキュメント代わりになるだけでなく、定義したルールが破られた際にブラウザの コンソール(Console) に警告を表示してくれるというメリットがあります。
6. オブジェクト形式での Props 定義
FoodItem.vue において、配列形式での定義ではなく、オブジェクト形式で定義します。これにより、各 Props の名前に加えてデータ型も指定できます。
FoodItem.vue:
<script>
export default {
// props: ['foodName','foodDesc','isFavorite'] ← 配列形式はコメントアウト
props: {
foodName: String,
foodDesc: String,
isFavorite: Boolean
}
}
</script>このように定義すれば、他の開発者が FoodItem.vue を見たときに、コンポーネントが何を期待しているか一目でわかります。もし親要素(App.vue)から間違ったデータ型の Props が渡されると、コンソールに警告が表示されます。
7. 必須項目(Required)の設定
特定の Props が必須であることを Vue に伝えるには、プロパティをさらにオブジェクトとして定義します。foodName を必須にする例です:
FoodItem.vue:
<script>
export default {
props: {
foodName: {
type: String,
required: true
},
foodDesc: String,
isFavorite: Boolean
}
}
</script>もし必須の Props が定義されずにコンポーネントが作成されると、開発者はコンソール警告を通じて間違いを即座に修正できます。
8. デフォルト値(Default Value)の設定
Props に デフォルト値(既定値) を設定することも可能です。foodDesc にデフォルト値を設定し、App.vue 側で説明文を定義せずにライスを表示してみましょう。
8.1 実装例:デフォルト値の活用
FoodItem.vue:
<script>
export default {
props: {
foodName: {
type: String,
required: true
},
foodDesc: {
type: String,
required: false,
default: 'これはデフォルトの説明文です。'
},
isFavorite: {
type: Boolean,
required: false,
default: false
}
}
}
</script>9. Props バリデータ関数
独自の バリデータ関数(Validator Function) を定義して、Props の値が有効かどうかを判定することもできます。
この関数は true または false を返す必要があります。false が返された場合、Props は無効とみなされ、開発モードのコンソールに警告が表示されます。
例えば、説明文の長さを 20 文字から 50 文字の間に制限したい場合、以下のように記述します。
FoodItem.vue:
<script>
export default {
props: {
foodName: {
type: String,
required: true
},
foodDesc: {
type: String,
required: false,
default: 'これはデフォルトの説明文です。',
validator: function(value) {
// 長さが20文字より大きく、50文字未満であるかチェック
if( 20 < value.length && value.length < 50 ) {
return true;
}
else {
return false;
}
}
},
isFavorite: Boolean
}
}
</script>10. Props の値を変更する(単一方向データフロー)
子コンポーネント内で、親から受け取った Props の値を直接変更することは 禁止 されています。Props は親コンポーネント(ここでは App.vue)からの一方通行のデータであり、子側では 読み取り専用(Read-only) です。
もし、以下のように Props を直接変更しようとするとエラーが発生します:
methods: {
toggleFavorite() {
// これはエラーになります!
this.isFavorite = !this.isFavorite;
}
}この制限を回避するには、受け取った Props を初期値として新しい データプロパティ(例:foodIsFavorite)を FoodItem.vue 内に作成します。
data の定義:
data() {
return {
foodIsFavorite: this.isFavorite
}
}これで、ユーザーがボタンをクリックしてこの新しいローカルデータを切り替えることが可能になります。
10.1 実装例:読み取り専用 Props をローカルデータへ変換
FoodItem.vue:
<template>
<div>
<h2>
{{ foodName }}
<img src="/img_quality.svg" v-show="foodIsFavorite">
</h2>
<p>{{ foodDesc }}</p>
<button v-on:click="toggleFavorite">お気に入り</button>
</div>
</template>
<script>
export default {
props: ['foodName', 'foodDesc', 'isFavorite'],
data() {
return {
// Props を初期値として受け取る
foodIsFavorite: this.isFavorite
}
},
methods: {
toggleFavorite() {
// ローカルデータなら変更可能
this.foodIsFavorite = !this.foodIsFavorite;
}
}
};
</script>
<style>
img {
height: 1.5em;
float: right;
}
</style>