親から props
経由で渡される Array<{ item: string, value: string|number, checked: boolean }>
みたいな物を v-for
で回してチェックボックスを描画した際に、 checked
の状態が変化しても HTML 要素として意図通りに描画されなくて困ったので、解決方法をメモします。
状況
v-for
を使ってチェックボックスのリストを描画している時に、
取り回している配列内の Object が変化しても、担当のチェックボックスの見た目上の状態が変化しなかった。
コードはざっくり以下のような感じ。
<dl>
<dt> hogehoge </dt>
<dd
v-for="item of list"
:key="`item-${item.value}`"
>
<input
:id="genDdId(item.value)"
:checked="item.checked"
:name="item.value"
type="checkbox"
@click.prevent="handleItemClick($event, item.value)"
>
<label :for="genDdId(item.value)">
{{ item.label }}
</label>
</dd>
</dl>
:checked="item.checked"
の真偽値が変化する度にチェックボックスの checked
属性が変化して欲しいけど、してくれない。
$forceUpdate
を試したけど変化無し。
原因と解決方法
原因
配列の変化は見てるけど、その各アイテムであるオブジェクトのプロパティまでは監視していないよ、という事だと推測。
普通に Vue.js の仕様に引っ掛かってしまっただけかも。
v-for
で繰り返し表示させる際は key
が必要になるわけだけど、この key
はリスト内の位置までしか担当してくれてないのかな。
Vue が各ノードの識別情報を追跡できるヒントを与えるために、また、先ほど説明したような既存の要素の再利用と並び替えができるように、一意な key 属性を全てのアイテムに与える必要があります。
解決方法
key
が違うなら異なる要素なので描画されるよね、と考えて、
状態により key
が常に変化するように仕組んで解決しました。
以下のイメージ。
<dd
v-for="item of list"
:key="`item-${item.value}--checked-${item.checked ? 1 : 0}`"
>