はじめに
Reactで開発を始めた方が最初につまずくポイントの一つが、「for文が使えない」という問題です。正確に言えば、JSXの中では直接for文を記述できません。
この記事では、なぜJSX内でfor文が使えないのか、そしてReactで繰り返し処理を行う正しい方法について解説します。
この記事で学べること
- JSXにおける式と文の違い
- map()メソッドを使った繰り返し処理の実装方法
- keyプロパティの重要性と正しい使い方
- どうしてもfor文を使いたい場合の対処法
JSXにおける式と文の違い
式と文の基本概念
JavaScriptには式(expression)と文(statement)という2つの概念があります。
式(expression)は、評価すると値を返すコードです。例えば以下のようなものが式に該当します。
// 式の例
1 + 2 // 3という値を返す
user.name // プロパティの値を返す
isActive ? 'active' : '' // 三項演算子は値を返す
[1, 2, 3].map(n => n * 2) // 新しい配列を返す
一方、文(statement)は、何らかの処理を実行するコードで、値を返しません。
// 文の例
if (isActive) { } // 条件分岐を実行
for (let i = 0; i < 10; i++) { } // ループ処理を実行
let count = 0; // 変数宣言を実行
なぜJSX内でfor文が使えないのか
JSXの中括弧{}内には、式しか記述できないという制約があります。これは、JSXが最終的にJavaScriptの関数呼び出しに変換されるためです。
// これはOK(式なので)
<div>{user.name}</div>
<div>{isActive ? 'アクティブ' : '非アクティブ'}</div>
// これはNG(文なので)
<div>{if (isActive) { return 'アクティブ' }}</div>
<div>{for (let i = 0; i < 10; i++) { }}</div>
以下の図は、JSXで使える構文と使えない構文を分類したものです。
Reactでの繰り返し処理:基本編
map()メソッドを使った実装
Reactで繰り返し処理を行う際は、配列のmap()メソッドを使うのが標準的な方法です。map()は新しい配列を返す式なので、JSX内で問題なく使用できます。
function UserList() {
const users = ['田中', '佐藤', '鈴木'];
return (
<ul>
{users.map((user, index) => (
<li key={index}>{user}</li>
))}
</ul>
);
}
このコードでは、users配列の各要素に対して<li>要素を生成しています。map()の第一引数は配列の各要素、第二引数はインデックスです。
基本的な配列のレンダリング例
数値の配列やオブジェクトの配列など、さまざまなデータ型に対応できます。
// 数値の配列
function NumberList() {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>
{numbers.map((number) => (
<li key={number}>{number}の2倍は{number * 2}</li>
))}
</ul>
);
}
// オブジェクトの配列
function ProductList() {
const products = [
{ id: 1, name: 'ノートPC', price: 120000 },
{ id: 2, name: 'マウス', price: 3000 },
{ id: 3, name: 'キーボード', price: 8000 }
];
return (
<ul>
{products.map((product) => (
<li key={product.id}>
{product.name}: {product.price.toLocaleString()}円
</li>
))}
</ul>
);
}
オブジェクトの配列を扱う場合は、各オブジェクトのプロパティにアクセスして表示できます。このように、map()を使えば柔軟にデータを表示できますね。
keyプロパティの重要性
keyが必要な理由
繰り返し処理で要素を生成する際、各要素には必ずkeyプロパティを指定する必要があります。keyはReactが要素を識別し、効率的に更新するために使用されます。
keyがないと、以下のような警告が表示されます。
Warning: Each child in a list should have a unique "key" prop.
Reactの差分検出とkeyの役割
Reactは仮想DOM(Virtual DOM)を使って、実際のDOMへの変更を最小限に抑えています。配列の要素が変更されたとき、keyがあることで、どの要素が追加・削除・移動されたのかを正確に判断できます。
適切なkeyの選び方
keyには、以下の優先順位で値を選びましょう。
1. 一意のID(推奨)
データベースから取得したIDなど、各要素を一意に識別できる値を使います。
const users = [
{ id: 'u001', name: '田中' },
{ id: 'u002', name: '佐藤' },
];
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
2. インデックス(条件付き)
データに一意のIDがない場合、配列のインデックスを使うこともできます。ただし、以下の条件を満たす場合のみ使用してください。
- 配列の並び替えが発生しない
- 要素の追加・削除が発生しない
- 配列が静的である
const staticList = ['リンゴ', 'バナナ', 'オレンジ'];
{staticList.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
よくある間違いとその影響
間違い1: keyを指定しない
// NG: keyがない
{users.map((user) => (
<li>{user.name}</li>
))}
この場合、Reactは警告を表示し、パフォーマンスが低下する可能性があります。
間違い2: インデックスを不適切に使用
// NG: 並び替えや削除がある場合
{users
.sort((a, b) => a.name.localeCompare(b.name))
.map((user, index) => (
<li key={index}>{user.name}</li>
))}
並び替え後もインデックスは0から始まるため、Reactは要素の入れ替わりを正しく検出できません。結果として、予期しない表示やパフォーマンス問題が発生します。
間違い3: ランダムな値を使用
// NG: 毎回異なる値が生成される
{users.map((user) => (
<li key={Math.random()}>{user.name}</li>
))}
再レンダリングのたびに新しいkeyが生成されるため、Reactは毎回全要素を再作成してしまいます。
どうしてもfor文を使いたい場合
JSX外でfor文を使う方法
JSX内では使えませんが、JSXの外でfor文を使って配列を構築することは可能です。
function UserList() {
const users = ['田中', '佐藤', '鈴木'];
const listItems = [];
// JSXの外でfor文を使用
for (let i = 0; i < users.length; i++) {
listItems.push(
<li key={i}>{users[i]}</li>
);
}
return <ul>{listItems}</ul>;
}
この方法なら、従来のfor文の構文をそのまま使えます。ただし、多くの場合はmap()を使う方がシンプルで読みやすいコードになります。
for...ofやforEachの活用
for...of文やforEach()メソッドも、JSXの外で使用できます。
for...of文を使う例
function UserList() {
const users = [
{ id: 1, name: '田中' },
{ id: 2, name: '佐藤' },
{ id: 3, name: '鈴木' }
];
const listItems = [];
for (const user of users) {
listItems.push(
<li key={user.id}>{user.name}</li>
);
}
return <ul>{listItems}</ul>;
}
forEachを使う例
function UserList() {
const users = ['田中', '佐藤', '鈴木'];
const listItems = [];
users.forEach((user, index) => {
listItems.push(
<li key={index}>{user}</li>
);
});
return <ul>{listItems}</ul>;
}
それぞれの使い分け
以下の表は、各方法の特徴と適している場面をまとめたものです。
| 方法 | 特徴 | 適している場面 |
|---|---|---|
| map() | 式として評価され、新しい配列を返す。JSX内で直接使用可能 | ほとんどの繰り返し処理(推奨) |
| for文 | 従来の繰り返し構文。JSXの外で使用 | 複雑な条件分岐や処理が必要な場合 |
| for...of | 配列の値を直接取得できる。JSXの外で使用 | インデックスが不要な場合 |
| forEach() | 配列メソッドとして使用。戻り値なし | 副作用を伴う処理(ただしReactでは非推奨) |
実際のReact開発では、map()メソッドを使うのが最も一般的で推奨される方法です。コードが簡潔になり、関数型プログラミングの考え方にも合致します。
まとめ
Reactでの繰り返し処理について、重要なポイントをまとめます。
Reactでの繰り返し処理のベストプラクティス
-
JSX内では式しか使えない
- for文は文なので、JSXの中括弧内に直接記述できません
- 式である配列のmap()メソッドを使用しましょう
-
map()メソッドを使うのが標準
- JSX内で直接使用できる
- コードが簡潔で読みやすい
- Reactの開発スタイルに適している
-
keyプロパティは必須
- 繰り返し処理で生成する要素には、必ずkeyを指定する
- 可能な限り一意のIDを使用する
- インデックスは、配列が静的な場合のみ使用する
-
for文も使える
- JSXの外で配列を構築すれば、for文も使用可能
- ただし、map()の方がシンプルなケースが多い