Vueの配列の変更が反映されないんだが


最終的にやりたかったこと

ツリー表示して選択されたデータを反映

公式のツリーのサンプル

https://jp.vuejs.org/v2/examples/tree-view.html
は使いたくないんだ
確かに楽なんだけど子コンポーネント孫コンポーネント作っちゃうと
データのバケツリレーになるからVuexを使わなければいけなくなるではないか。。。!
なので子コンポーネント化せずにがんばった

やってみた

動かない
v-forでリストレンダリングしてるツリー構造の部分がクリックしても開閉せず
しかしクリックイベントは拾ってデータの変更はされている
配列がリアクティブじゃないぞ。。。。

配列の挙動の検証

<template>
  <div>
    <ul>
      <li v-for="(item, index) in list" :key="index"> {{ item }} </li>
    </ul>
    {{ list }}
    <button @click="incrementArray">+1</button>
  </div>
</template>

<script>
export default {
  name: 'Sample',
  data() {
    return {
      list: [1, 2, 3, 4, 5]
    }
  },
  methods: {
    incrementArray() {
      this.list[0] = this.list[0] + 1;
      console.log(this.list);
    }
  }
}
</script>

あかん、反映されへんぞ。。。なんやこれ。。。

しかしコンソールログを見ると値は増えてるから
原因は再描画されていないことだな

調べた参考になる記事

要するに

  • push() pop() shift() unshift() splice() sort() reverse() を使えば変更を検知して再描画するぞ!!
  • 普通に代入すると検知しないぞ!!
  • 配列とオブジェクトに要素を増やしたり減らしたりするときはthis.$set()を使え!!」

なるほどね

修正していく

上記メソッド無駄に走らせて強制発火パターン

<script>
export default {
  name: 'Sample',
  data() {
    return {
      list: [1, 2, 3, 4, 5]
    }
  },
  methods: {
    incrementArray() {
      this.list[0] = this.list[0] + 1;
      this.list.splice();
    }
  }
}
</script>


おお〜

一見イケてない実装だけど
表示してる配列に変更はないけど別の変数の状態が表示に影響している場合は
こうするしかないかもしれない
v-forの中で別の変数をv-showv-ifで参照してる時とか

this.list.push({});
this.list.pop();

とか

this.list.unshift({});
this.list.shift();

とか試したけど
強制発火させるならsplice()が一番速かった

this.$setを使うパターン

<script>
export default {
  name: 'Sample',
  data() {
    return {
      list: [1, 2, 3, 4, 5]
    }
  },
  methods: {
    incrementArray() {
      this.$set(this.list, 0, this.list[0] + 1);
    }
  }
}
</script>

表示に使っているデータに変更を直接加える場合はこれがいい
あとは上記メソッド使ったり

配列とオブジェクトは特殊なんですね

次回はツリー表示したチェックボックスのやつの記事でも書きます
渋ってないでツリーを子コンポーネント化してVuexデビューしようかな。。。