vueに慣れている人であれば当たり前の話だと思いますが、
結構ググっているとkeyにindexを使っての解説を目にする事があったので、
何番煎じか分かりませんが、自身のアウトプットの為に備忘録していきます。
※vue.jsをこれから学んで行く人向けです。
v-forディレクティブとは
vueで配列に基づいて、リストレンダリングする為に使用するディレクティブです。
所謂for文としての使い方をします。 単数形 in 複数形
のような構文を用います。
複数形の部分がソースの配列で、単数形の部分は配列要素が反復されているエイリアスなので、変数のように設定が可能になっています。別に単数形でなくても動きます。
<div id="app">
<ul>
<li v-for="item in items">{{ item }}</li>
</ul>
</div>
参考:リストレンダリング
v-forは2つ目の引数にindexを取れる
何番目のデータかを確認する時などに使用する事もあるかと思いますが、
以下のように第2引数を指定する事で、indexを取る事が出来ます。ここもindexではなく、iやjなどでも動きます。
<div id="app">
<ul>
<li v-for="(item, index) in items">{{ item }}</li>
</ul>
</div>
オブジェクトにも使えるv-for
オブジェクトに対しても、バリューで回してあげる事が出来ます。この辺は簡単ですね。
<div id="app">
<ul>
<li v-for="value in object">{{ value }}</li>
</ul>
</div>
オブジェクトの時は第2、第3引数の設定が出来ます
短刀直入に言うと、第2引数にはオブジェクトキーを指定出来て、第3引数でindexを設定する事が可能となっています。
<div id="app">
<ul>
<li v-for="(value, key, index) in object">{{ value }}</li>
</ul>
</div>
数値に対しても使えるv-for
数値でもOK
<div id="app">
<ul>
<li v-for="n in 10">{{ value }}</li>
</ul>
</div>
そろそろ本題
まずはv-forにはキー属性をつけましょうと言う話です。
公式にも書いてある内容にはなりますが、v-forは要素の変更について極力使えるものは再利用するようなアルゴリズムになっているそうです。
その為、vueがノードの識別情報を追跡できるように一意なkey属性を全てのアイテムに与える必要があります。
<div id="app">
<ul>
<div v-for="item in items">
<input type="text">
</div>
</ul>
<button @click="remove">削除</button>
</div>
<script>
export default {
data() {
return {
items: ['えんぴつ','消しゴム','定規'],
};
},
methods: {
remove: function() {
this.items.shift()
}
}
})
</script>
このようなコードがあったとして、実行すると配列の分だけ、今回は3回リストレンダリングされ、インプットフォームが表示されます。またv-onディレクティブで設定したremoveメソッドによって、先頭要素を削除する設計になっています。
ここでkey属性を設定せずに3つのフォームに対して、仮に別々の内容を入力していたとし、
先頭を削除するremoveを実行すると、先頭の'えんぴつ'要素は消えるのですが、レンダリングされる際に入力したフォームは最後尾の内容が削除されてしまいます。
①②③のフォームに対して、要素①を削除してもフォームの中身は③が消えてしまう、と言うような状況が起こりえます。
このような問題を避ける為にVueがノードを識別する事が出来るようにv-forを使用する時はkey属性を使う事が推奨されています。
<div id="app">
<ul>
<div v-for="item in items" :key="item">
<input type="text">
</div>
</ul>
<button @click="remove">削除</button>
</div>
<script>
export default {
data() {
return {
items: ['えんぴつ','消しゴム','定規'],
};
},
methods: {
remove: function() {
this.items.shift()
}
}
})
</script>
そう、v-forではkey属性を付けた方がいいのですが、このkeyにindexを入れてしまうとまた困った事が起きてしまいます。
<div id="app">
<ul>
<div v-for="(item, index) in items" :key="index">
<input type="text">
</div>
</ul>
<button @click="remove">削除</button>
</div>
<script>
export default {
data() {
return {
items: ['えんぴつ','消しゴム','定規'],
};
},
methods: {
remove: function() {
this.items.shift()
}
}
})
</script>
ここで言うindexは配列の中が削除されたりする事で変動しますよね。
えんぴつが削除されたら、消しゴムが0、定規が1に変動しますよね。そう言う事です。配列のlengthやステータスを管理するメソッドが上手く動かない事があって突き詰めて行った結果がこれでした。
ハマったと言っても公式ドキュメントを読んで直ぐに解決出来ました。良い勉強になりました。