dataプロパティに登録したオブジェクトの変更を検出する方法

はじめに

Vue.jsはインスタンスが持つプロパティ(dataやprops)の変更を検知して、DOMの内容を変更したり、イベントの発火を行うことができます😇
しかし、Vue.jsのドキュメントに以下のようなことが書いてあります。

モダンな JavaScript の制限(そして Object.observe の断念)のため、Vue.js はプロパティの追加または削除を検出できません。Vue.js はインスタンスの初期化中に、getter/setter 変換処理を実行するため、プロパティは、Vue がそれを変換しそしてそれをリアクティブにするために、data オブジェクトに存在しなければなりません。

Vue.jsはプロパティの追加または削除を検出できません。👈コレ

Vueはすでに作成されたインスタンスに対して動的に新しいルートレベルのリアクティブなプロパティを追加することはできません。
簡単に説明すると、JavaScriptの制限(Object.observe)によって、dataやprops配下のオブジェクトの変更を検知することができないということです😷💦
つまり、いつものようなやり方でオブジェクトを変更すると、変更が検出されません😩

オブジェクトの変更検出の注意

以下のような処理では、動的に追加したプロパティは無視されてしまいます😷

<script>
  export default {
    data: () => ({
      tags: {
        name: 'タグ'
      }
    }),
    methods: {
      addColor () {
        this.tags.color = '#E84B3C'
      }
    }
  }
</script>

変更を検出する方法

先ほど、「Vueはすでに作成されたインスタンスに新しいルートレベルのリアクティブプロパティを動的に追加することはできません。」とあったのですが、
以下の方法でネストされたオブジェクトにリアクティブなプロパティを追加することが可能です✌️

1.vm.$setをつかう

vm.$setインスタンスメソッドを使えば、
オブジェクトにリアクティブなプロパティを追加することができます😇

<script>
  export default {
    data: () => ({
      tags: {
        name: 'タグ'
      }
    }),
    methods: {
      addColor () {
        this.$set(this.tags, 'color', '#E84B3C')
      }
    }
  }
</script>

vm.$setVue.setのエイリアスです。

2.Object.assign()をつかう

複数のプロパティを割り当てたい場合は、Object.assign()が便利です😇
このような場合、変更を検知するのではなく、元のオブジェクトと、追加するオブジェクトの両方のプロパティを持つ新たなオブジェクトが作られることになります。

<script>
  export default {
    data: () => ({
      tags: {
        name: 'タグ'
      }
    }),
    methods: {
      addColor () {
        this.tags = Object.assign({}, this.tags, {id: 1, color: '#E84B3C'})
      }
    }
  }
</script>

Object.assign()は、IE非対応なので注意してください💦
ブラウザ実装状況はこちら

3.vm.$deleteをつかう

逆にプロパティを削除する場合はvm.$deleteを使います。

<script>
  export default {
    data: () => ({
      tags: {
        name: 'タグ',
        color: '#E84B3C'
      }
    }),
    methods: {
      deleteColor () {
        this.$delete(this.tags, 'color')
      }
    }
  }
</script>

vm.$deleteVue.deleteのエイリアスです。

まとめ

VueがObject.definePropertyを使用して、
オブジェクトをgetter/setterに変換することでリアクティブを実現しているんですね😇

しかし、Vueインスタンスに渡したオブジェクトは、
プレーンなJavaScriptオブジェクトのように扱ってはいけないことには注意が必要ですね😷

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.