ReactでTypeError: Cannot read properties of undefined (reading 'map')を修正する方法

beginner⚛️ React2026-03-19| React 16以降、Node.js 14以降、ブラウザ(Chrome/Firefox/Safari)、Next.js、Create React App、Vite

Error Message

TypeError: Cannot read properties of undefined (reading 'map')
#react#undefined#state#props

要約

undefined に対して .map() を呼び出しています。フォールバックを追加するだけで解決します:

// クラッシュする
{items.map(item => <li key={item.id}>{item.name}</li>)}

// 安全
{(items ?? []).map(item => <li key={item.id}>{item.name}</li>)}

エラーの全文

TypeError: Cannot read properties of undefined (reading 'map')
    at ProductList (ProductList.jsx:12)
    at renderWithHooks (react-dom.development.js:14985)

React はコンポーネントを同期的にレンダリングします。最初のレンダリング時に productsundefined だと — ほんの一瞬であっても — .map() の呼び出しは即座に失敗します。猶予はありません。

原因

1. ステートが空配列ではなく undefined で初期化されている

// 誤り — 引数なしの useState() はデフォルトで undefined になる
const [products, setProducts] = useState();

// 正しい
const [products, setProducts] = useState([]);

2. APIデータがまだ読み込まれていない

useEffect は最初のレンダリングのに実行されます。そのため、初回描画時のステートは初期化した値のまま — つまり何もない状態かもしれません。

useEffect(() => {
  fetch('/api/products')
    .then(res => res.json())
    .then(data => setProducts(data)); // 最初のレンダリングの後に届く
}, []);

3. 親コンポーネントと子コンポーネントでプロップ名が異なる

// 親は 'items' として渡している
<ProductList items={products} />

// 子は 'data' として読んでいる — これは undefined になる
function ProductList({ data }) {
  return data.map(...); // クラッシュ
}

4. APIレスポンスの構造が想定と異なる

// 想定: [{ id: 1, name: 'Widget' }, ...]
// 実際のAPIレスポンス: { data: [...], total: 42 }

setProducts(response); // products にオブジェクトがセットされ、配列にならない

これは多くの人がはまるポイントです。構造を決めつける前に、必ず生のレスポンスをログに出力しましょう。

修正手順

修正1:ステートを空配列で初期化する

最もよくある原因です。配列のステートを undefined のままにしてはいけません。

const [products, setProducts] = useState([]); // ✅

修正2:マッピング前にフォールバックを追加する

どこまで防御的に書くかに応じて、3つの選択肢があります:

// オプションA: Null合体演算子(undefined/null に対して最もシンプル)
{(products ?? []).map(product => (
  <li key={product.id}>{product.name}</li>
))}

// オプションB: オプショナルチェーン(undefined の場合は何も描画しない)
{products?.map(product => (
  <li key={product.id}>{product.name}</li>
))}

// オプションC: Array.isArray(最も明示的)
{Array.isArray(products) && products.map(product => (
  <li key={product.id}>{product.name}</li>
))}

値がオブジェクト、null、または数値になる可能性がある場合(単に undefined だけでなく)は、Array.isArray() を使いましょう。3つの中で最も堅牢な方法です。

修正3:非同期データのローディング状態を管理する

function ProductList() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/products')
      .then(res => res.json())
      .then(data => {
        setProducts(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>読み込み中...</p>;

  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

修正4:APIレスポンスを使用前に確認する

fetch('/api/products')
  .then(res => res.json())
  .then(data => {
    console.log(data); // 構造を決めつける前に必ずログを確認する

    // APIが { data: [...], total: 42 } 形式で返す場合
    setProducts(data.data ?? data);
  });

修正5:開発時にプロップの型を強制する

誤ったプロップ名を、混乱したバグ報告が届く前に — 本番環境に到達する前に — キャッチしましょう。

// PropTypes
import PropTypes from 'prop-types';

ProductList.propTypes = {
  items: PropTypes.array.isRequired,
};

ProductList.defaultProps = {
  items: [],
};
// TypeScript — コンパイル時の強制、実行時コストなし
interface ProductListProps {
  items: Product[];
}

function ProductList({ items }: ProductListProps) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

デバッグチェックリスト

  • DevTools を開いてスタックトレースを確認する — クラッシュが発生した正確なファイルと行番号が表示されます
  • .map() の直前に console.log(yourVariable) を追加して、最初のレンダリング時に実際にどんな値が入っているか確認する
  • useState の呼び出しを確認する — 初期値は undefined ですか、それとも [] ですか?
  • 親コンポーネントで渡しているプロップ名と、子コンポーネントで分割代入しているプロップ名を比較する — タイポ1つで十分クラッシュします
  • setState を呼び出す前に生のAPIレスポンスをログに出力して、配列が想定した場所にあることを確認する

修正の確認

修正を適用した後、4つの点を確認してください:

  • ブラウザのコンソールを開く — TypeError が消えているはずです。
  • 実際のデータでリストが正しく表示される。
  • DevTools の Network タブで Slow 3G にスロットリングして非同期パスをストレステストする。
  • 空配列レスポンスでテストする — クラッシュせず、空のリストが表示されるだけであることを確認。

クイックリファレンス

| 原因                              | 修正                                          |
|-----------------------------------|-----------------------------------------------|
| 初期値なしの useState()           | useState([])                                  |
| 最初のレンダリング時の非同期データ | ローディング状態 + 条件付きレンダリング        |
| 誤ったプロップ名                  | 親と子でプロップ名を一致させる                |
| APIが配列でなくオブジェクトを返す | setProducts(response.data ?? response)        |
| 親からの null になりうるプロップ  | defaultProps または ?? [] フォールバック      |

Related Error Notes