はじめに (対象読者・この記事でわかること)

本記事は、React で JSX 内に array の map() を記述する際に遭遇しやすいエラーについて、初心者から中級者を対象に解説します。具体的には “Cannot read property 'map' of undefined” や “Each child in a list should have a unique 'key' prop” といった典型的な例を取り上げ、エラーの原因、デバッグ手順、実装上のベストプラクティスを体系的に学べます。React 開発を始めたばかりの方や、既存コードでエラーが頻発して困っている方に役立つ内容です。

前提知識

  • 基本的な JavaScript(変数、配列、関数)の理解
  • React のコンポーネント構造と JSX の基本的な書き方
  • ES6 の import/export、アロー関数、prop-types などのモダンな記法

React JSX で map() を使うときのエラー概要

React のコンポーネントは JSX で UI を宣言的に記述しますが、リスト表示を行う際に配列の map() メソッドを多用します。map() は配列要素を走査し、各要素に対して JSX 要素を返すことで効率的なリスト生成を可能にします。しかし、JSX 内で map() をそのまま書くと、データが未定義だったり、キー属性が欠如していたりすることでランタイムエラーが発生します。これらのエラーはコンパイルは通りますが、ブラウザ上で例外が投げられ、画面が真っ白になるか、コンソールに警告が出力されて開発者の手を止めてしまいます。したがって、正しいデータ取得、null 安全性の確保、キーの一意性保証といった前提条件を理解し、適切に実装することが重要です。

map() エラーの詳細と対処法

ステップ1:データの有無を確認し、デフォルト値を設定する

map() を呼び出す前に対象が確実に配列であることを保証します。undefinednull が渡されると Cannot read property 'map' of undefined が発生します。以下のようにデフォルト値(空配列)を設定すると安全です。

Tsx
type Props = { items?: Item[]; }; const List: React.FC<Props> = ({ items = [] }) => { return ( <ul> {items.map(item => ( <li key={item.id}>{item.name}</li> ))} </ul> ); };

上記では itemsundefined の場合でも [] が代入され、map() が安全に実行されます。

ステップ2:key プロパティの付与と一意性の確保

React はリスト再描画時に各要素を識別するため key が必要です。key が重複したり欠如したりすると Each child in a list should have a unique "key" prop という警告がコンソールに出ます。id がユニークであればそれを使い、無い場合はインデックスの使用は最後の手段とします。

Tsx
{items.map((item, index) => ( <li key={item.id ?? `fallback-${index}`}>{item.name}</li> ))}

ハマった点やエラー解決

発生したエラー 発生原因 見落としがちポイント
Cannot read property 'map' of undefined props.items が非同期取得中に undefined useEffect でデータ取得直後に描画が走る
Each child in a list should have a unique "key" prop keyitem.name など重複しやすい値を使用 id がサーバー側で重複していたケース
Objects are not valid as a React child map() 内でオブジェクトそのものを返している JSX 内に {item} と書いたまま

解決策

  1. データ取得のタイミングを調整
    useEffect で非同期に取得したデータはステートに格納し、ステートが nullundefined のときはローディング UI を表示します。

```tsx const [items, setItems] = useState(null);

useEffect(() => { fetch('/api/items') .then(res => res.json()) .then(data => setItems(data)) .catch(() => setItems([])); }, []);

if (!items) return ; ```

  1. 型定義で配列保証
    TypeScript を使う場合は items: Item[] と明示し、null 許容したいときは Item[] | null と書くことでコンパイル時に抜け漏れを検知できます。

  2. key の一意性を徹底
    - 常にサーバー側でユニーク ID(UUID など)を持たせる
    - フロントエンドで生成する場合は crypto.randomUUID() を利用
    - インデックスは リストが変化しない 場合にだけ使用

  3. リファクタリングで map() を切り出す
    長い map() ロジックは別コンポーネントに分割すると可読性が向上し、エラー箇所が特定しやすくなります。

```tsx const ItemRow: React.FC<{item: Item}> = ({item}) => (

  • {item.name}
  • );

    // 親コンポーネント

      {items.map(item => )}

    ```

    以上の手順を踏むことで、JSX 内で map() を使用したときに起きやすいエラーを予防・解決できます。

    まとめ

    本記事では、React の JSX 内で map() を使う際に頻出する 「null/undefined に対する map 呼び出し」「key の欠如・重複」 という二大エラーの原因と対策を解説しました。

    • データが未定義でも安全に走らせる:デフォルト値や型ガードで配列保証
    • key の一意性を徹底:サーバー側でユニーク ID を持たせ、インデックスは最終手段
    • 非同期取得とローディング UI:取得前はスピナーで代替表示し、ステートが null のときに描画しない

    これらを実践すれば、コンソールエラーに悩まされることなく、スムーズにリストレンダリングが行えるようになります。次回は React の Virtual DOM と差分更新アルゴリズム に焦点を当て、パフォーマンス最適化のテクニックを紹介する予定です。

    参考資料