ReactのJSXでリストを表示するとき .map() を使う理由とkey propの役割

React

こんにちは、白々さじきです。

今回は、Reactでリスト(配列のデータ)をJSXに表示するときの書き方についてまとめます。

JavaScriptを学んできた人は「ループは for 文で書く」という感覚があると思います。Reactでも最初は for 文を書こうとして、うまくいかないことがあります。

結論

JSXの中では for 文は使えません。.map() を使います。また、繰り返しで生成した要素には必ず key prop を付けます。

なぜ for 文が使えないのか

JSXの {} の中に書けるのは「式(expression)」だけです。for 文は「文(statement)」なので書けません。

種類JSXの中で使えるか
list.map(...), condition ? A : B使える
for (...), if (...) {}使えない

.map() は配列を別の配列に変換して返す「式」なので、JSXの中に書けます。

type Shop = { id: string; name: string };

// NG: JSXの中にfor文は書けない
const ShopList = ({ shops }: { shops: Shop[] }) => {
  return (
    <ul>
      {for (const shop of shops) {  // SyntaxError
        <li>{shop.name}</li>
      }}
    </ul>
  );
};

// OK: .map() を使う
const ShopList = ({ shops }: { shops: Shop[] }) => {
  return (
    <ul>
      {shops.map((shop) => (
        <li key={shop.id}>{shop.name}</li>
      ))}
    </ul>
  );
};

.map() の書き方

.map() は配列の各要素に関数を適用して、新しい配列を返します。

// shops の各要素に対して <li> を返す → <li> の配列ができる
shops.map((shop) => (
  <li key={shop.id}>{shop.name}</li>
))

JSXを複数行に書くときは () で囲みます。

// 1行のとき
shops.map((shop) => <li key={shop.id}>{shop.name}</li>)

// 複数行のとき(カッコで囲む)
shops.map((shop) => (
  <li key={shop.id}>
    <span>{shop.name}</span>
    <span>{shop.address}</span>
  </li>
))

key prop が必要な理由

.map() で生成した要素には key を付けないと警告が出ます。

Warning: Each child in a list should have a unique "key" prop.

Reactはリストが更新されたとき(要素の追加・削除・並び替え)に、どの要素が変わったかを識別する必要があります。key はその識別子として使われます。

// NG: key がない
shops.map((shop) => <li>{shop.name}</li>)

// NG: インデックスを key にする(並び替え時に不具合が起きやすい)
shops.map((shop, i) => <li key={i}>{shop.name}</li>)

// OK: ユニークなIDを key にする
shops.map((shop) => <li key={shop.id}>{shop.name}</li>)

key にはリスト内で一意な値を使います。データに id フィールドがある場合はそれが最適です。

Google Maps でマーカーを複数表示する例

地図系のコンポーネントでも同じパターンを使います。地図は1つで、マーカーだけ .map() で複数生成します。

// NG: 地図ごと複数作ってしまう
{shops.map((shop) => (
  <Map>
    <AdvancedMarker position={shop.position} />
  </Map>
))}

// OK: 地図は1つ、マーカーだけ .map()
<Map defaultCenter={center} defaultZoom={12}>
  {shops.map((shop) => (
    <AdvancedMarker key={shop.id} position={shop.position} />
  ))}
</Map>

まとめ

  • JSXの {} の中には「式」しか書けないため for 文は使えない
  • .map() は配列を返す「式」なのでJSXの中で使える
  • .map() で生成した要素には一意な key prop を付ける
  • key にはインデックスではなくデータの id を使う

最初は「なんで for 文が書けないんだろう」と思いましたが、JSXが「式の世界」だと理解してからはすっきりしました。

参考リンク

サポートのお願い

下記リンクからお買い物いただけると、ブログ運営のための費用が増え、有料サービスを利用した記事作成が可能になります。ご協力よろしくお願いします!



コメント

タイトルとURLをコピーしました