画面が真っ白になる原因誰もが一度は経験したことがあるでしょう。綺麗なリストコンポーネントを書き終え、ブラウザをリロードした瞬間、データが表示される代わりに真っ白な画面が表示される。コンソールを開くと、そこには犯人がいます。TypeError: data.map is not a functionです。
このエラーは、JavaScriptの.map()メソッドがArray(配列)プロトタイプにのみ存在するために発生します。変数がオブジェクト、文字列、null、またはundefinedの場合、エンジンはどう処理すべきか判断できません。Reactのエコシステムでは、これは通常、ステートや外部APIからのデータフローのどこかに問題があることを示しています。
正確なエラーメッセージ```
TypeError: data.map is not a function
## エラーが発生する理由私の経験上、これらのクラッシュの90%は以下の3つのパターンのいずれかに当てはまります:
- **初期値が空:** ステートを`null`で初期化したり空のままにしたりしたが、最初のAPIコールが完了する前にJSXがレンダリングしようとした。- **ラッパーオブジェクト:** APIが`{ "users": [1, 2, 3] }`のようなレスポンスを返したが、`users`配列ではなくトップレベルのオブジェクトに対してmapを実行しようとした。- **単一の結果:** 項目が1つしか見つからなかった場合に、バックエンドが配列ではなく単一のオブジェクトを返した。## 解決方法### 1. ステートを正しく初期化するReactコンポーネントは、`useEffect`フックがデータの取得を開始する前に、少なくとも一度はレンダリングされます。ステートを`undefined`で初期化すると、最初のレンダリングで`undefined.map()`が呼び出され、即座にクラッシュします。
**問題のあるコード:**
const [items, setItems] = useState(); // デフォルトはundefined
return (
解決策: 常に空の配列 [] をデフォルト値にします。これにより、データが実際に届くまで何も表示せずに、最初のレンダリングを正常に完了させることができます。
const [items, setItems] = useState([]); // 安全で予測可能
2. オプショナルチェーンを使用するデータが常に配列であることを保証できない場合は、オプショナルチェーン演算子(?.)が非常に役立ちます。これは安全装置として機能します。変数がnullまたはundefinedの場合、式はエラーをスローせずにundefinedを返します。
return (
<ul>
{data?.map(user => (
<li key={user.id}>{user.username}</li>
))}
</ul>
);
3. APIレスポンスの構造を確認する多くの開発者は response.data が必要な配列であると考えがちです。しかし、最近のAPIは結果をメタデータでラップすることがよくあります。例えば、50個の製品を期待しているのに、APIが { "count": 50, "products": [...] } を返す場合です。レスポンス自体にmapを適用しようとすると、レスポンスはJSONオブジェクトであるため失敗します。
解決策: フェッチ直後にデータの構造を確認してください。ステートが null にならないよう、フォールバックを使用します。
useEffect(() => {
axios.get('/api/products').then(res => {
// ラッパーではなく配列をセットするようにする
setProducts(res.data.products || []);
});
}, []);
4. 防御的な型チェックを追加する予測不可能なレガシーシステムを扱う場合、厳格なガード句が必要になることがあります。Array.isArray() を使用すると、データが実際にループ可能である場合にのみコードを実行するように保証できます。
if (!Array.isArray(data)) {
return <p>読み込み中、または無効なデータ形式です...</p>;
}
return data.map(item => <div>{item.title}</div>);
確認手順修正を適用したら、以下の手順で確認してください:
- コンソールの確認: Chrome DevTools (F12) を開き、ハードリフレッシュ後に赤いエラーテキストが消えていることを確認します。- React DevTools: コンポーネントの「Hooks」セクションを確認します。ステートが空の配列
[]から始まっていることを確認してください。- ネットワークスロットリング: Networkタブで「Slow 3G」設定を使用します。これにより、配列が届くまでの「待機期間」にUIがクラッシュせずに処理できるかをテストできます。## 未然に防ぐためのベストプラクティス- TypeScript: ステートの型を厳格に定義します(例:useState<User[]>([]))。これにより、実行時ではなく開発中にmapエラーをキャッチできます。- Propsのデフォルト値: 子コンポーネントがリストを受け取る場合は、分割代入のデフォルト値を使用します:const List = ({ items = [] }) => { ... }- データのサニタイズ: 外部APIのデータは常に信頼できないものとして扱います。ローカルステートに保存する前に、必要な形式にマップまたはフィルタリングしてください。

