v-forとv-ifの併用はダメらしいんで対策した件
v-forとv-ifを同一タグで使っちゃダメだよ!
公式が言っています。
v-for と同じ要素に v-if を使わないでください。
こうしたくなってしまう2つの一般的なケースがあります:
リスト内のアイテムをフィルタする(例: v-for="user in users" v-if="user.isActive")。このような場合は、フィルタリングされたリストを返却する算出プロパティに users を置き換えてください(例: activeUsers)。
非表示にする必要がある場合、リストを描画しないようにする(例: v-for="user in users" v-if="shouldShowUsers")。このような場合は、v-if をコンテナ要素(例: ul、ol)に移動してください。
じゃあ、どうすればいいのってところを調べました。
どうして併用したらダメなのか
理由は毎回リスト全体を繰り返し処理するのは非効率的でパフォーマンスが悪いからです。
2つの解決策
解決策①
computedを利用して、リストをフィルターにかけておいて表示したい要素だけを抽出しておいてv-forで処理する方法。
解決策②
v-ifをラッパー要素(<template>とか<div>とかの他の要素をグループ化する要素)に設置し、そこを通った場合のみv-forで処理するという方法です。
具体的に見てみると
解決策①
ビフォー
<ul>
<li
v-for = "todo in todos"
:key = "todo.id"
v-if = "todo.status === '作業中'"
>
{{ todo }}
</li>
アフター
<ul>
<li
v-for = "todo in doingTodo"
:key = "todo.id"
>
{{ todo }}
</li>
~~~
computed: {
doingTodo:function() {
//条件に合う要素のみを抽出する処理
}
computed(算出プロパティ)においてdoingTodoを定義し、ビフォーのtodosの所にアフターではdoingTodoを使用します。
それによって全リストが繰り返しされるよりもはるかに効率的になる。
ちなみに、methodsでdoingTodoを定義しても同じことができるがcomputedを使用するほうが早い。
解決策②
ビフォー
<ul>
<li
v-for = "todo in todos"
:key = "todo.id"
v-if = "todo.status === '作業中'"
>
{{ todo }}
</li>
アフター
<ul v-if="shouldShowTodos">
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo }}
</li>
</ul>
ラッパー要素(ul)にv-ifを設置することで、条件に合う要素のみv-forで処理される。
ToDoリストにおける実践例
ToDoの状態(作業中/完了)ごとに表示を切り替えたかった時にv-ifとv-showを使っていたのを書き換えました。
"作業中"のtodoを表示する。
v-forとv-ifを併用してしまっている。
todos: [
{id:0 comment:'料理' status:'作業中'}
{id:1 comment:'掃除' status:'完了'}
{id:2 comment:'選択' status:'作業中'}
]
<tbody v-for = "(todo, index) in todos" :key= "index" v-if="todo.status === '作業中'">
<th>{{ todo.id }}</th>
<th>{{ todo.comment }}</th>
<th>{{ todo.satus }}</th>
filter()を使い、todosから"作業中"のtodoのみを抜き出して新しい配列doingTodoを作成する。
doingTodo: function(){
this.todos.filter(e => { e.status === '作業中'})
}
<tbody v-for = "(todo, index) in doingTodo" :key= "index">
<th>{{ todo.id }}</th>
<th>{{ todo.comment }}</th>
<th>{{ todo.satus }}</th>
まとめ
・v-forとv-ifが併用したいシチュエーションの時には解決策が2つあります。
・できるだけ効率化しましょう!というのがVue.jsの方針。
(っていうかプログラミング言語全般そうなんじゃないかと思いますが。)