今回やること
前回は、JavaScriptのitemオブジェクトを使って、
一覧画面に1件分のデータを表示しました。
今回は、複数のデータを配列にまとめ、
map()を使ってテーブルへ一覧表示します。
あわせて、Reactで一覧を表示するときに必要になる
keyについても確認します。
公開日:更新日:
前回は、JavaScriptのitemオブジェクトを使って、
一覧画面に1件分のデータを表示しました。
今回は、複数のデータを配列にまとめ、
map()を使ってテーブルへ一覧表示します。
あわせて、Reactで一覧を表示するときに必要になる
keyについても確認します。
前回は、1つのitemオブジェクトを用意しました。
今回は複数のデータを扱うため、複数のオブジェクトを配列にまとめます。
itemをitemsに変更し、
[]の中に2つのオブジェクトを用意しましょう。
const items = [
{
id: "sample-1",
name: "はじめてのWebデザイン本",
category: "本",
status: "気になる",
price: 2200,
memo: "図が多くて読みやすそう",
},
{
id: "sample-2",
name: "小さなサイドテーブル",
category: "家具",
status: "欲しい",
price: 3500,
memo: "部屋に置きやすそう",
},
];
itemsは配列で、その中に2つのオブジェクトが入っています。
items 配列
↓
[
{ 1件目のデータ },
{ 2件目のデータ }
]
前回は、1件分のデータをh3やpで表示しました。
今回は複数件を一覧として並べるため、HTMLのtableを使います。
まずは、items配列の1件目をテーブルに表示してみましょう。
配列の1件目はitems[0]で取り出せます。
items[0].name
items[0]で1件目のオブジェクトを取り出し、
.nameでその中のnameプロパティを取り出しています。
これまでは画面を区別しやすくするために、
<h2 className="screen-title">一覧画面</h2>
という見出しを表示していました。
今回から一覧の内容をテーブルで表示するため、この「一覧画面」の見出しは削除します。
あわせて、前回の一覧画面にあったh3やpの部分を、
次のテーブルに置き換えましょう。
<table>
<thead>
<tr>
<th>名前</th>
<th>カテゴリ</th>
<th>ステータス</th>
<th>価格</th>
<th>メモ</th>
</tr>
</thead>
<tbody>
<tr>
<td>{items[0].name}</td>
<td>{items[0].category}</td>
<td>{items[0].status}</td>
<td>{items[0].price}円</td>
<td>{items[0].memo}</td>
</tr>
</tbody>
</table>
ファイルを保存して、ブラウザを確認してみましょう。
「はじめてのWebデザイン本」がテーブルに1件表示されればOKです。
では、2件目も表示するとしたらどうなるでしょうか。
2件目はitems[1]で取り出せるので、もう1つtrを書けば表示できます。
<tr>
<td>{items[1].name}</td>
<td>{items[1].category}</td>
<td>{items[1].status}</td>
<td>{items[1].price}円</td>
<td>{items[1].memo}</td>
</tr>
2件ならこの方法でも書けますが、
データが10件、20件と増えるたびに、同じ形のtrを追加するのは大変です。
そこで、配列のデータを1件ずつ処理できるmap()を使います。
tbodyの中を、map()を使った書き方に変更してみましょう。
詳しい仕組みは、実際に一覧表示したあとで整理します。
<tbody>
{items.map((item) => (
<tr>
<td>{item.name}</td>
<td>{item.category}</td>
<td>{item.status}</td>
<td>{item.price}円</td>
<td>{item.memo}</td>
</tr>
))}
</tbody>
ファイルを保存して、ブラウザを確認してみましょう。
「はじめてのWebデザイン本」と「小さなサイドテーブル」の2件が表示されればOKです。
map()はJavaScriptの配列メソッドです。
配列の要素を1件ずつ処理して、その結果から新しい配列を作れます。
先ほど使ったコードの中心部分は、次の形です。
items.map((item) => {
// itemを使った処理
});
items配列の中からデータを1件ずつ取り出し、
そのとき処理している1件をitemとして扱います。
items
↓
配列全体
map()
↓
配列の要素を1件ずつ処理する
item
↓
そのとき処理している1件分のオブジェクト
1回目の処理では、itemは
「はじめてのWebデザイン本」のオブジェクトになります。
item.name
// "はじめてのWebデザイン本"
2回目の処理では、itemは
「小さなサイドテーブル」のオブジェクトになります。
item.name
// "小さなサイドテーブル"
つまり、items[0]やitems[1]を自分で書き分けなくても、
map()が配列のデータを順番に処理してくれます。
今回は、map()の中でそのときのitemを使って
trを1行ずつ作っています。
1件目
item.name → "はじめてのWebデザイン本"
↓
1行目のtrを作る
2件目
item.name → "小さなサイドテーブル"
↓
2行目のtrを作る
また、items.map(...)はJavaScriptの式なので、
JSXの中で使うために外側を{}で囲んでいます。
{items.map((item) => (
// JSX
))}
一覧表示の仕組みを確認できたところで、開発者ツールのConsoleも見てみましょう。
この時点では、keyに関する警告が表示されています。
画面には問題なく2件表示されていますが、 Reactで一覧を表示するときには、もう1つ必要な設定があります。
Consoleに表示されていた警告は、
繰り返して作った要素にkeyが指定されていないことを知らせるものです。
Reactでmap()を使って一覧を表示するときは、
繰り返して作る各要素にkeyを指定します。
keyは、Reactが一覧の各要素を
識別するために使う値です。
今回のデータには、それぞれidが用意されています。
1件目はsample-1、2件目はsample-2です。
keyには、
同じ一覧の中で重複せず、データを安定して識別できる値を使うのが基本です。
そのため、今回はこのidをkeyに使います。
それでは、先ほどのtrにkeyを追加してみましょう。
map()の中のtrを、次のように変更します。
<tr key={item.id}>
1件目ではsample-1、
2件目ではsample-2がkeyとして使われます。
ファイルを保存して、もう一度開発者ツールのConsoleを確認してみましょう。
先ほど表示されていたkeyに関する警告が消えていればOKです。
今回登場した内容を、ReactとJavaScriptに分けて整理します。
| 種類 | 今回登場したもの |
|---|---|
| React | key、JSXの{}を使った一覧表示 |
| JavaScript | 配列、オブジェクト、map() |
items配列を作ったり、
map()で1件ずつ処理したりする部分はJavaScriptです。
そのJavaScriptの処理によって作ったJSXをReactで表示し、
各要素を識別するためにkeyを指定しています。
items配列にまとめたitems[0]で配列の1件目を取り出せるmap()で配列のデータを1件ずつ処理できるmap()を使って同じtrを件数分作ったmap()を使うときは{}で囲むkeyを指定するidがある場合は、安定したidをkeyに使う
今回のApp.jsxの完成コードです。
前回までの画面切り替えを残したまま、
items配列をmap()でテーブル表示します。
import { useState } from "react";
export default function App() {
const items = [
{
id: "sample-1",
name: "はじめてのWebデザイン本",
category: "本",
status: "気になる",
price: 2200,
memo: "図が多くて読みやすそう",
},
{
id: "sample-2",
name: "小さなサイドテーブル",
category: "家具",
status: "欲しい",
price: 3500,
memo: "部屋に置きやすそう",
},
];
const [screen, setScreen] = useState("list");
if (screen === "create") {
return (
<main className="form-screen">
<header className="screen-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button
type="button"
className="secondary"
onClick={() => setScreen("list")}
>
一覧へ
</button>
</div>
</header>
<h2 className="screen-title">新規登録画面</h2>
</main>
);
}
if (screen === "edit") {
return (
<main className="form-screen">
<header className="screen-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button
type="button"
className="secondary"
onClick={() => setScreen("list")}
>
一覧へ
</button>
</div>
</header>
<h2 className="screen-title edit-title">編集画面</h2>
</main>
);
}
return (
<main className="list-screen">
<header className="list-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" onClick={() => setScreen("create")}>
新規登録
</button>
<button type="button" onClick={() => setScreen("edit")}>
編集
</button>
</div>
</header>
<table>
<thead>
<tr>
<th>名前</th>
<th>カテゴリ</th>
<th>ステータス</th>
<th>価格</th>
<th>メモ</th>
</tr>
</thead>
<tbody>
{items.map((item) => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.category}</td>
<td>{item.status}</td>
<td>{item.price}円</td>
<td>{item.memo}</td>
</tr>
))}
</tbody>
</table>
</main>
);
}