LoginSignup
130

More than 3 years have passed since last update.

[Vue.js] なぜpropsのdefault値にObjectやArrayを指定する際にfactory関数にする必要があるのか

Last updated at Posted at 2018-12-16

あなたがこの記事を見ているということは、コンソールに以下のワーニングが出ていることでしょう。

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をデフォルト値としたい場合、関数を指定する必要があるのでしょうか。

ワーニングを無視すると何が起こるか

まず、ワーニングを無視した場合に何が起こるのか試してみます。

AppCounter.vue
<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コンポーネントです。

App.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つ配置して動かしてみると、以下のような結果になります。
counter01.gif
どちらのボタンをクリックしても、2つのカウンターがインクリメントされています。

↓のリンクから実際に触っていただけます。
Edit Vue Template

オブジェクトや配列は値がコピーされず、参照が共有される

propsのデフォルト値に指定したオブジェクトや配列は、値がコピーされることなく参照が共有されます。
そのため、複数のvueインスタンスが同一のObjectを参照し、同一のObjectに変更を加えてしまう状況が発生します。

2つのカウンターがどちらのボタンの操作でもインクリメントされるのは、このためです。

ワーニングを出すのではなく、フレームワーク側でObjectや配列を自動でディープコピーしてくれればいいのでは?と考えることもできるのですが、開発者側でファクトリー関数を指定できるようにすることで、ディープコピーにまつわるリスクを抑えつつ、実装の選択肢を広げ自由度を上げる目的があるようです。

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
130