console.lealog();

@leader22のWeb系に関する勉強めもブログですのだ

Vue.jsでViewにバインドした配列を更新するとv-repeatしてるViewがおかしくなる問題(があった

まさかの3日で過去の話になりました。
現時点で最新のv0.10.1ではなおってます!

某人のおかげか、こんな僻地ブログまでも来てくださる方が多いようですありがたやー。
そんなあなたにVue.jsネタをひとつ。

タイトルが長いわりに、問題なのか、仕様なのかわかってないんですけど。

Vue.jsのバージョンは0.9.3です。
まずは以下を見てください。

参考:Vue.js use array with v-repeat, then update...?@0.10.1
参考:Vue.js use array with v-repeat, then update...?@0.9.3

なんとなくわかりましたかね。

v-repeatしてる配列を更新すると表示がバグる

いちおうソースを再掲。

<div id="js-main-view">
  <ul v-with="sample">
    <li>arr: {{arr}} -> <span v-repeat="arr">{{$value}}</span> <- ここに注目</li>
    <li>obj: {{obj}} -> <span v-repeat="obj">{{$value}}</span></li>
  </ul>
  updated_at: {{updated}}
</div>

なんてことないhtmlと、

var len = 10;
// [1,0,1,0,0,0,1,0,1,0] みたいなの返すだけ
function makeArr() {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr[i] = Math.random() * 2|0;
  }
  return arr;
}

// {"_0":1,"_1":0,"_2":1,"_3":1,"_4":1,"_5":0,"_6":1,"_7":1,"_8":0,"_9":0} みたいなの返すだけ
function makeObj() {
  var obj = {};
  for (var i = 0; i < len; i++) {
    obj['_'+i] = Math.random() * 2|0;
  }
  return obj;
}

// いつものやつ
var vm = new Vue({
  el: '#js-main-view',
  data: {
    sample: {
      arr: makeArr(),
      obj: makeObj()
    },
    updated: new Date().toLocaleString()
  }
});

// 2000ms毎に表示を更新
setInterval(function() {
  vm.sample = {
    arr: makeArr(), // これで表示が残念なことに
    obj: makeObj() // Objectだとセーフ
  };
  vm.updated = new Date().toLocaleString();
}, 2000);

そのまんまです。

いちおう回避策

上の例のように、配列を使わずに、オブジェクトで代用すればなんとか。
いや、なんでやねんなんですけど。

ちゃんと中身は更新されてるので、v-repeatしてないなら問題ないんかね。

教えてえらい人

本家のドキュメントにあるコレ。

You should avoid directly setting elements of a data-bound Array with indices, because those changes will not be picked up by Vue.js. Instead, use the agumented set() method.

配列使うなら直接ぶっこまないでね、って書いてるのはコレのことでよいのかしら?
とはいえreplaceもsetも使いにくい気がするんですけど・・・。

どうするのが一番良いのか、わかった人はぜひ教えてください。