「TypeError: Cannot read property ‘map’ of undefined」(未定義のプロパティ’map’を読み取ることができません)は、Reactアプリで発生する可能性のあるエラーメッセージです。ややデバッグが複雑になる可能性もありますが、この記事がお役に立てるはずです。

以下、主な原因と解決策を詳しくご紹介していきます。経験豊富なReact開発者であっても、Reactをこれから使い始める人であっても、エラーを効率的に解消して、アプリ開発を軌道に乗せましょう。

「TypeError: Cannot read property ‘map’ of undefined」エラーの原因

「TypeError: Cannot read property ‘map’ of undefined」エラーは通常、Reactのコード内に未定義の値のプロパティや関数にアクセスしようとすると発生します。

簡単に言えば、初期化されていない配列やデータを受け取っていない配列など、未定義の値をマッピングしようとするとエラーが引き起こされます。

例えば、以下のコードでは、JSON PlaceholderデータからTodo項目を取得していますが、APIリクエストからのデータが到着する前にmap関数が呼び出されています。

import { useState, useEffect } from 'react';

function App() {
  const [todos, setTodos] = useState();

  useEffect(() => {
    const getTodos = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos?_limit=5'
      );
      const data = await response.json();
      setTodos(data);
    };
    getTodos();
  }, []);

  console.log(todos);

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>
          <h2>Item: {todo.title}</h2>
        </div>
      ))}
    </div>
  );
}

export default App;

こうなると、「TypeError: Cannot read property ‘map’ of undefined」エラーが発生します。

「TypeError: Cannot read property ‘map’ of undefined」エラー
「TypeError: Cannot read property ‘map’ of undefined」エラー

配列にデータが入る前からReactにTodoのstate変数が配列であることを伝える方法を確保するから、Todoのstate変数がAPIリクエストからデータを取得するまでmap関数を実行しないようにしなければなりません。

「TypeError: Cannot read property ‘map’ of undefined」エラーの解決方法

「TypeError: Cannot read property ‘map’ of undefined」エラーを解決する方法は、以下の3通りあります。

  1. state変数を空の配列に初期化する
  2. 比較演算子を使用する
  3. オプショナルチェーン(?.演算子)を使用する

それぞれの解決方法を順にご紹介します。

1. state変数を空の配列に初期化する

まず手始めに、マッピングしようとしている配列変数が定義されているかどうかを確認します。

state変数をデフォルトで空の配列に初期化することで、その変数が常に存在するようになり、マッピングしてもエラーが返されなくなります。

例えば、以下は2つの似たようなコンポーネントですが、1つ目のstate変数は空の配列に初期化されておらず、2つ目は初期化されています。

// state変数を空の配列に初期化する前
function MyComponent() {
  const [myList, setMyList] = useState();
  
  return (
    <ul>
      {myList.map(item => <li>{item}</li>)}
    </ul>
  );
}

// state変数を空の配列に初期化した後
function MyComponent() {
  const [myList, setMyList] = useState([]);

  return (
    <ul>
      {myList.map(item => <li>{item}</li>)}
    </ul>
  );
}

この例では、useState([])を使用して、myListstate変数がデフォルトで空の配列になっています。これにより、myListが最初は未定義であっても、常に配列となるため、エラーを回避することができます。

データ取得の例として、todosstate変数を空の配列([])に初期化することも可能です。

import { useState, useEffect } from 'react';

function App() {
  // stateをTodoの空の配列に初期化する
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    const getTodos = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos?_limit=5'
      );
      const data = await response.json();
      setTodos(data);
    };
    getTodos();
  }, []);

  console.log(todos);

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>
          <h2>Item: {todo.title}</h2>
       </div>
      ))}
    </div>
  );
}

export default App;

2. 比較演算子を使用する

配列変数にマッピングする前に、比較演算子を使ってその変数が定義されているかどうかをチェックするのも有効です。これには、三項演算子や論理AND演算子(&&)を使用します。

以下は、三項演算子の使用例です。

function MyComponent() {
  const [myList, setMyList] = useState();

  return (
    <ul>
      {myList ? myList.map(item => <li>{item}</li>) : null}
    </ul>
  );
}

上記は、myList配列変数が定義されているかどうかを確認してから、変数にマッピングする例です。myListが定義されていない場合、三項演算子はnullを返し、何もレンダリングされません。myListが定義されていれば、map関数が呼び出され、リストの項目がレンダリングされます。

論理AND演算子を使用してもほぼ同じです。

function MyComponent() {
  const [myList, setMyList] = useState();

  return (
    <ul>
      {myList && myList.map(item => <li>{item}</li>)}
    </ul>
  );
}

三項演算子のような比較演算子を使用すると、読み込みの処理を行うことができるため、APIからデータを取得している間、別のものが画面に表示されます。

import { useState, useEffect } from 'react';

function App() {
  const [todos, setTodos] = useState();

  useEffect(() => {
    const getTodos = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos?_limit=5'
      );
      const data = await response.json();
      setTodos(data);
    };
    getTodos();
  }, []);

  console.log(todos);

  return (
   <div>
      {todos ? (
        todos.map((todo) => (
          <div key={todo.id}>
            <h2>Item: {todo.title}</h2>
          </div>
        ))
      ) : (
        <h1>Loading...</h1>
      )}
    </div>
  );
}

export default App;

3. オプショナルチェーン(?.演算子)を使用する

ES2020で導入されたオプショナルチェーン(?.演算子)を使用すると、配列のmap関数のようなプロパティや関数に安全にアクセスできます。

以下は、myListstate変数を確認するために、オプショナルチェーンを使用する関数コンポーネントの例です。

function MyComponent() {
  const [myList, setMyList] = useState();

  return (
    <div>
      {myList?.map((item) => (
        <p>{item}</p>
      ))}
    </div>
  );
}

上の例では、myList配列変数に安全にアクセスするためにオプショナルチェーンが使用されています。myListが未定義の場合、何もレンダリングされず、myListが定義されていれば、map関数が呼び出され、リスト項目がレンダリングされます。

まとめ

「TypeError: Cannot read property ‘map’ of undefined」は、未定義の値やnull値に対してmap関数を使用すると発生するエラーです。

解決策は3つありますが、2つ目にご紹介した比較演算子を使用する方法では、APIが空のレスポンスやnull値を送信することを回避できるため、最も汎用性が高いと言えます。

受け取るデータが配列かどうかわからない場合は、map関数を呼び出す前にデータ型を確認して変換する関数を追加することも可能です。

Reactプロジェクトを構築する際には、Kinstaのアプリケーションホスティングをぜひ一度お試しください。

このエラーに遭遇した経験はありますか?(もしそうであれば)どのように解決しましたか?以下のコメント欄でぜひお聞かせください。