Vue 3のComposition APIでリストレンダリングを行うには、主にv-for
ディレクティブを使い、リアクティブなデータソース(ref
やreactive
で作成)をループ処理します。
基本的なリストレンダリング
基本的なリストレンダリングは、配列データをv-for
で繰り返し描画します。
例:文字列の配列を表示する
<script setup>
import { ref } from 'vue';
// リアクティブな配列を定義
const fruits = ref(['🍎 りんご', '🍌 バナナ', '🍊 みかん']);
</script>
<template>
<ul>
<li v-for="fruit in fruits" :key="fruit">
{{ fruit }}
</li>
</ul>
</template>
ポイント
-
ref
:ref
を使って配列をリアクティブなデータにします。これにより、配列が変更されると自動的にUIが更新されます。 -
v-for
:v-for="item in items"
という形式で配列の各要素を繰り返します。 -
:key
:key
属性は、Vueが各ノードを識別し、効率的に描画を更新するために必須です。各要素で一意となる値を指定してください。要素に安定したIDがある場合はそれを使用するのがベストです。
オブジェクトの配列のレンダリング
実際のアプリケーションでは、オブジェクトの配列を扱うことがほとんどです。
例:ユーザー情報のリストを表示する
<script setup>
import { ref } from 'vue';
const users = ref([
{ id: 1, name: '山田 太郎', email: 'taro@example.com' },
{ id: 2, name: '鈴木 花子', email: 'hanako@example.com' },
{ id: 3, name: '佐藤 次郎', email: 'jiro@example.com' }
]);
</script>
<template>
<div>
<h2>ユーザーリスト</h2>
<ul>
<li v-for="user in users" :key="user.id">
<p><strong>名前:</strong> {{ user.name }}</p>
<p><strong>Email:</strong> {{ user.email }}</p>
</li>
</ul>
</div>
</template>
ポイント
- この例では、各ユーザーオブジェクトが持つ一意の
id
を:key
にバインドしています。これは、リストの要素が追加、削除、または並べ替えられたときに、Vueが正確に変更を追跡するための最も確実な方法です。
インデックスの取得
v-for
では、要素と共にそのインデックスも取得できます。
<template>
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index }}: {{ item.name }}
</li>
</ul>
</template>
注意: 配列のインデックスを:key
として使用することは、リストが以下のような特徴を持つ場合に限り推奨されます。
- リストが決して並べ替えられない。
- リストが決してフィルタリングされない。
- リストの要素が追加・削除される際、常に末尾でのみ行われる。
これらの条件を満たさない場合、インデックスをキーとして使うと、パフォーマンスの低下や状態の不整合を引き起こす可能性があります。
可能な限り、一意なIDをキーとして使用してください。
リストの操作
Composition APIでは、リアクティブな配列を直接変更するメソッドを定義して、リストを動的に操作できます。
例:アイテムの追加と削除
<script setup>
import { ref } from 'vue';
const items = ref([
{ id: 1, text: 'タスク1' },
{ id: 2, text: 'タスク2' }
]);
const newItemText = ref('');
let nextId = 3;
function addItem() {
if (newItemText.value.trim() === '') return;
items.value.push({
id: nextId++,
text: newItemText.value
});
newItemText.value = ''; // 入力欄をクリア
}
function removeItem(idToRemove) {
items.value = items.value.filter(item => item.id !== idToRemove);
}
</script>
<template>
<div>
<input v-model="newItemText" @keyup.enter="addItem" placeholder="新しいタスクを入力">
<button @click="addItem">追加</button>
<ul>
<li v-for="item in items" :key="item.id">
<span>{{ item.text }}</span>
<button @click="removeItem(item.id)">削除</button>
</li>
</ul>
</div>
</template>
ポイント
-
追加:
items.value.push()
のように、ref
で作成した配列の.value
プロパティに直接アクセスして配列操作メソッドを呼び出します。 -
削除:
filter
メソッドを使って特定の要素を除外した新しい配列を生成し、items.value
に再代入しています。Vueはこの変更を検知してUIを更新します。 -
イベントハンドリング:
@click
や@keyup.enter
を使ってユーザーの操作とメソッドを紐付けます。
reactive
を使ったリストレンダリング
ref
の代わりにreactive
を使って、オブジェクトや配列をリアクティブにすることも可能です。reactive
はオブジェクトの深い階層までリアクティブにします。
<script setup>
import { reactive } from 'vue';
const state = reactive({
users: [
{ id: 1, name: '田中' },
{ id: 2, name: '伊藤' }
]
});
function addUser() {
state.users.push({ id: Date.now(), name: '新規ユーザー' });
}
</script>
<template>
<button @click="addUser">ユーザー追加</button>
<ul>
<li v-for="user in state.users" :key="user.id">
{{ user.name }}
</li>
</ul>
</template>
ref
とreactive
の使い分け
-
ref
: プリミティブ値(数値、文字列など)や、配列やオブジェクト全体を再代入する可能性がある場合によく使われます。
.value
を介してアクセスする必要があります。 -
reactive
: オブジェクトや配列に特化しており、.value
なしで直接プロパティにアクセスできます。
トップレベルでの再代入はリアクティビティを失うため注意が必要です。
リストレンダリングにおいては、どちらを使っても機能しますが、コンポーネント内での状態管理のスタイルに合わせて選択すると良いでしょう。
一般的には、コンポーネントのトップレベルの状態として配列を管理する場合はref
がシンプルで分かりやすいことが多いです。