いま3枚のカードを手で書いています。8羽にするなら8回コピー——さすがにつらいです。データを配列にして、そこから自動で並べます。
データをJavaScriptのファイルに置く
まずは表示から切り離して、データだけをまとめます。
export const birds = [
{
id: 1,
name: 'シマエナガ',
emoji: '🐦',
area: '北海道',
rare: 3,
memo: '雪のようにまっ白な小鳥。ふわふわの丸い体。',
},
{
id: 2,
name: 'スズメ',
emoji: '🐤',
area: 'まちなか',
rare: 1,
memo: 'いちばん身近な小鳥。ちゅんちゅん鳴いている。',
},
// …このあと8羽ぶん続く
]export defaultではなく名前つきのexportにしました。データのファイルには複数のまとまりを置くこともあるためです。読みこむ側は波かっこが要ります。
import { birds } from './data/birds.js'mapでカードに変える
配列を一覧にするのは、この4行です。
<div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{birds.map((bird) => (
<BirdCard key={bird.id} name={bird.name} emoji={bird.emoji} area={bird.area} memo={bird.memo} />
))}
</div>やっていることは、前回JavaScriptの回で見たmapそのものです。
// 文字列の配列 → 文字列の配列
names.map((name) => `🐦 ${name}`)
// オブジェクトの配列 → JSXの配列
birds.map((bird) => <BirdCard … />)変換後の中身がJSXになっただけで、mapの使い方は同じです。JSXの配列を波かっこの中に置くと、Reactが順番に並べて表示します。
keyは何のためにあるのか
mapでJSXを作ると、Reactが必ずこう言ってきます。
Warning: Each child in a list should have a unique "key" prop.keyは、Reactが「どの要素がどのデータのものか」を見分けるための目印です。
Reactは画面を作り直すとき、前回のJSXと今回のJSXを見比べて、変わったところだけを書きかえます。並び順が変わったとき、keyが無いと「1番目と2番目が入れかわった」のか「1番目と2番目の中身が両方書きかわった」のかを区別できません。
keyがあれば、中身ではなく目印で追いかけられるので、要素をそのまま動かすだけで済みます。
<BirdCard key={bird.id} … />件数もデータから出す
「全8羽」と手で書いていた部分も、配列から出せます。
<p className="mt-1 text-sm text-slate-500">全{birds.length}羽をあつめよう</p>データを1羽足すだけで、カードも件数も同時に増えます。冒頭の回で見た「データと画面がズレる」問題が、ここで消えました。
並べ方はTailwindのグリッドで
カードが8枚になると、縦一列では長すぎます。画面幅に応じて列を増やします。
<div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">スマホは1列、sm以上で2列、lg以上で3列。HTMLに書くときとまったく同じクラスです。Reactだからといって特別な書き方は要りません。
sm:やlg:の考え方はTailwindコースのこの回に。Reactの中でも規則は同じです公式ドキュメントも見てみる
ja.react.dev外部サイトリストのレンダー – React公式の「リストのレンダー」。「配列の項目に順序を保つためのkeyを与える」の節に、keyの決まりとindexを避ける理由がまとまっていますこのレッスンのまとめ
- データは配列にまとめ、
export constで書き出す(受け取りは波かっこつき) - 一覧は
mapでJSXの配列に変換して、波かっこの中に置く forEachやreturn忘れは画面が真っ白になる定番の原因keyはReactが要素を見分けるための目印。データのidを使う- indexをkeyにすると、並べかえたときに状態が別の行へ移る
- 件数も
birds.lengthから出せば、データと表示がズレなくなる
次は、条件によって出し分ける方法です。レアな鳥にだけバッジを付けて、説明がまだ無い鳥には別の文を出します。
