1. なぜ Vue 2 では props の型がオブジェクトまたは配列の場合、デフォルト値は必ず関数である必要があるのか?
Vue 2 では、props の型がオブジェクト(Object)または配列(Array)の場合、デフォルト値として関数を使用することが推奨されている理由は以下の通りです:
-
オブジェクトの特性:javascriptではオブジェクトはデフォルトでミュータブルです。直接オブジェクトをデフォルト値として設定すると、そのデフォルト値はメモリ上で共有され、デフォルト値を使用するすべてのコンポーネントインスタンスが同じオブジェクトの参照を共有することになります。
JavaScript において、プリミティブ以外をオブジェクトと呼ばれます
プリミティブ (primitive、プリミティブ値、プリミティブデータ型) はオブジェクトでなく、メソッドを持たないデータのことです。
以下の内容は、読みやすさと理解を容易にするために、オブジェクトと配列のまま記述しています。しかし、上記の説明に基づき、JavaScriptにおいて配列はオブジェクトに属することをご了承ください
-
潜在的なデータ汚染:これにより、あるコンポーネントインスタンスがこのオブジェクトや配列を変更した場合、その変更がデフォルト値を使用しているすべての他のコンポーネントインスタンスに影響を及ぼすことになります。これは通常、私たちが期待する動作ではありません。
-
新しいインスタンスを返す関数の使用:この問題を避けるために、Vue はこのような参照型の props に対して、デフォルト値を新しいオブジェクトまたは配列インスタンスを返す関数で指定することを要求します。こうすることで、新しいコンポーネントインスタンスを作成するたびにこの関数が呼ばれ、それぞれのインスタンスに独立した、他のインスタンスと共有されないデフォルト値が提供されます。
例:
props: {
items: {
type: Array,
default: () => [] // 新しい空の配列をデフォルト値として返す
},
config: {
type: Object,
default: () => ({}) // 新しい空のオブジェクトをデフォルト値として返す
}
}
このようにすることで、各コンポーネントインスタンスの items
と config
prop は、それぞれ独立したデフォルト値のコピーを持つことになり、データの隔離性が保証され、潜在的なデータの交差汚染問題を防ぐことができます。
2. Vue 2 における props の値の型とデフォルト値設定
2.1. props の値の型
Vue 2 では、props の値にはさまざまな型があり、以下のようなものが含まれますが、これに限定されません:
- String(文字列)
- Number(数値)
- Boolean(真偽値)
- Array(配列)
- Object(オブジェクト)
- Function(関数)
- Date(日時)
- Symbol(シンボル) - より新しいバージョンの Vue および JavaScript 環境で使用可能
- null および undefined - props の型やデフォルト値としても使用できます
これらの props のデフォルト値を設定する際、原始的な型(文字列、数値、真偽値など)には直接値を代入できますが、オブジェクトの場合は、新しいインスタンスを返すファクトリ関数を通じてデフォルト値を設定する必要があります。これにより、各コンポーネントインスタンスが共有されることなく、常に新しいインスタンスを取得できるようになります。
2.2. props デフォルト値設定の例
以下は、異なる型の props とそのデフォルト値設定の例です:
Vue.component('my-component', {
props: {
// 文字列型、デフォルトは空文字列
text: {
type: String,
default: ''
},
// 数値型、デフォルトは0
count: {
type: Number,
default: 0
},
// 真偽値型、デフォルトはfalse
isActive: {
type: Boolean,
default: false
},
// 配列型、デフォルトは空配列
items: {
type: Array,
default: () => []
},
// オブジェクト型、デフォルトは空オブジェクト
config: {
type: Object,
default: () => ({})
},
// 関数型、デフォルトは空関数
callback: {
type: Function,
default: () => {}
},
// 日時型、デフォルトは現在の日時
date: {
type: Date,
default: () => new Date()
}
},
// ...その他のコンポーネントロジック
});
上記の例では、配列、オブジェクト、および日時などの複雑な型に対しては(実際にはすべてオブジェクトですが、理解しやすくするためにこのように書いています)、矢印関数を使用して新しいインスタンスを返すことで、異なるコンポーネントインスタンス間で同じデフォルト値を共有する問題を避けています。一方、文字列、数値、真偽値などの基本型に対しては、直接デフォルト値を設定できます。関数型に関しては、参照型ではないものの、一貫性を保つために矢印関数を使用してデフォルト値を定義することが推奨されます。