あなたがこの記事を見ているということは、コンソールに以下のワーニングが出ていることでしょう。
WARN
[Vue warn]: Invalid default value for prop "XXX": Props with type Object/Array must use a factory function to return the default value.
このワーニングはVueコンポーネントのprops
に関するものです。
「propsのdefaultの値にObjectやArrayを使用したい場合、ファクトリー関数を指定しろ」
という内容のワーニングです。
ワーニングを解消する
以下のようにコードを修正することでワーニングを解消できます。
修正前
props: {
obj: {
type : Object,
require : false,
'default': { count: 0 } // Objectをそのまま指定している
},
}
修正後
props: {
obj: {
type : Object,
require : false,
'default': () => ({ count: 0 }) // Objectを生成する関数を指定する
},
}
なぜ関数を指定する必要があるのか
なぜ、ObjectやArrayをデフォルト値としたい場合、関数を指定する必要があるのでしょうか。
ワーニングを無視すると何が起こるか
まず、ワーニングを無視した場合に何が起こるのか試してみます。
<template>
<div class="content">
<span>{{ obj.count }}</span>
<button @click="obj.count++;">+1</button>
</div>
</template>
<script>
export default {
props: {
obj: {
type: Object,
require: false,
'default': { count: 0 } // ワーニングを無視して、Objectをそのまま指定している
}
}
};
</script>
「+1」ボタンのクリックでカウンターをインクリメントする、Vueコンポーネントです。
<template>
<div id="app">
<app-counter />
<app-counter />
</div>
</template>
<script>
import AppCounter from "./components/AppCounter";
export default {
name: "App",
components: {
AppCounter
}
};
</script>
そのカウンターを2つ配置して動かしてみると、以下のような結果になります。
どちらのボタンをクリックしても、2つのカウンターがインクリメントされています。
オブジェクトや配列は値がコピーされず、参照が共有される
propsのデフォルト値に指定したオブジェクトや配列は、値がコピーされることなく参照が共有されます。
そのため、複数のvueインスタンスが同一のObjectを参照し、同一のObjectに変更を加えてしまう状況が発生します。
2つのカウンターがどちらのボタンの操作でもインクリメントされるのは、このためです。
ワーニングを出すのではなく、フレームワーク側でObjectや配列を自動でディープコピーしてくれればいいのでは?と考えることもできるのですが、開発者側でファクトリー関数を指定できるようにすることで、ディープコピーにまつわるリスクを抑えつつ、実装の選択肢を広げ自由度を上げる目的があるようです。
参考