多くの場合、データのコレクションから複数の類似したコンポーネントを表示したいと思うでしょう。JavaScript の配列メソッドを使用して、データの配列を操作できます。このページでは、React で filter()
と map()
を使用して、データの配列をフィルタリングおよび変換し、コンポーネントの配列に変換する方法を学びます。JavaScript 配列メソッド
学習内容
- JavaScript の
map()
を使用して配列からコンポーネントをレンダリングする方法 - JavaScript の
filter()
を使用して特定のコンポーネントのみをレンダリングする方法 - React キーを使用するタイミングと理由
配列からのデータのレンダリング
コンテンツのリストがあるとします。
<ul>
<li>Creola Katherine Johnson: mathematician</li>
<li>Mario José Molina-Pasquel Henríquez: chemist</li>
<li>Mohammad Abdus Salam: physicist</li>
<li>Percy Lavon Julian: chemist</li>
<li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>
これらのリスト項目の違いは、コンテンツ、つまりデータだけです。インターフェースを構築する際には、コメントのリストからプロフィール画像のギャラリーまで、異なるデータを使用して同じコンポーネントの複数のインスタンスを表示する必要があることがよくあります。このような状況では、そのデータを JavaScript のオブジェクトと配列に格納し、map()
や filter()
などのメソッドを使用して、それらからコンポーネントのリストをレンダリングできます。
配列から項目のリストを生成する簡単な例を以下に示します。
- 移動 データを配列に移動します
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
- マップ
people
メンバーを JSX ノードの新しい配列listItems
にマップします
const listItems = people.map(person => <li>{person}</li>);
- 戻り値 コンポーネントから
listItems
を<ul>
で囲んで返します
return <ul>{listItems}</ul>;
結果はこちらです
const people = [ 'Creola Katherine Johnson: mathematician', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; }
上記のサンドボックスにコンソールエラーが表示されていることに注意してください
このエラーの修正方法については、このページの後半で説明します。その前に、データに構造を追加しましょう。
項目の配列のフィルタリング
このデータはさらに構造化できます。
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'physicist',
}, {
id: 3,
name: 'Percy Lavon Julian',
profession: 'chemist',
}, {
id: 4,
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
}];
職業が 'chemist'
の人のみを表示する方法が必要だとします。JavaScript の filter()
メソッドを使用して、それらの人だけを返すことができます。このメソッドは、項目の配列を受け取り、「テスト」(true
または false
を返す関数)に通し、テストに合格した(true
を返した)項目のみの新しい配列を返します。
profession
が 'chemist'
である項目のみが必要な場合、「テスト」関数は (person) => person.profession === 'chemist'
のようになります。以下にまとめ方を示します。
- 作成
people
にfilter()
を呼び出して、person.profession === 'chemist'
でフィルタリングすることにより、「化学者」のみの新しい配列chemists
を作成します
const chemists = people.filter(person =>
person.profession === 'chemist'
);
- 次に、マップ
chemists
をマップします
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
known for {person.accomplishment}
</p>
</li>
);
- 最後に、コンポーネントから
listItems
を返します
return <ul>{listItems}</ul>;
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => person.profession === 'chemist' ); const listItems = chemists.map(person => <li> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return <ul>{listItems}</ul>; }
`key` を使用してリスト項目の順序を保持する
上記のすべてのサンドボックスは、コンソールにエラーを表示していることに注意してください。
各配列項目に `key` を付ける必要があります。これは、その配列内の他の項目の中で一意に識別する文字列または数値です。
<li key={person.id}>...</li>
キーは、各コンポーネントがどの配列項目に対応するかを React に伝え、後でそれらを一致させることができます。これは、配列項目が移動(例:ソートによる)、挿入、または削除される可能性がある場合に重要になります。適切に選択された `key` は、React が何が起こったかを正確に推測し、DOM ツリーを正しく更新するのに役立ちます。
キーをその場で生成するのではなく、データに含める必要があります。
export const people = [{ id: 0, // Used in JSX as a key name: 'Creola Katherine Johnson', profession: 'mathematician', accomplishment: 'spaceflight calculations', imageId: 'MK3eW3A' }, { id: 1, // Used in JSX as a key name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist', accomplishment: 'discovery of Arctic ozone hole', imageId: 'mynHUSa' }, { id: 2, // Used in JSX as a key name: 'Mohammad Abdus Salam', profession: 'physicist', accomplishment: 'electromagnetism theory', imageId: 'bE7W1ji' }, { id: 3, // Used in JSX as a key name: 'Percy Lavon Julian', profession: 'chemist', accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', imageId: 'IOjWm71' }, { id: 4, // Used in JSX as a key name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist', accomplishment: 'white dwarf star mass calculations', imageId: 'lrWQx8l' }];
詳細
各項目が 1 つではなく、複数の DOM ノードをレンダリングする必要がある場合はどうすればよいでしょうか?
短い <>...</> フラグメント 構文ではキーを渡すことができないため、単一の `<div>` にグループ化するか、少し長く、より明示的な `<Fragment>` 構文を使用する必要があります。
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
フラグメントは DOM から消えるため、これは `<h1>`、`<p>`、`<h1>`、`<p>` などのフラットなリストを生成します.
`key` を取得する場所...
データソースが異なれば、キーのソースも異なります。
- データベースからのデータ: データがデータベースからのものである場合は、本質的に一意であるデータベースキー/ ID を使用できます。
- ローカルで生成されたデータ: データがローカルで生成および永続化される場合(例:メモ帳アプリのメモ)、インクリメントカウンター、`crypto.randomUUID()`、または `uuid` のようなパッケージを項目の作成時に使用します。
キーのルール...
- キーは兄弟間で一意である必要があります。 ただし、異なる配列の JSX ノードに同じキーを使用しても問題ありません。
- キーは変更しないでください。変更すると、目的が損なわれます! レンダリング中に生成しないでください。
React にキーが必要な理由...
デスクトップ上のファイルに名前がないと想像してみてください。代わりに、順序(最初のファイル、2 番目のファイルなど)で参照します。慣れることはできますが、ファイルを削除すると混乱が生じます。2 番目のファイルが最初のファイルになり、3 番目のファイルが 2 番目のファイルになり、というようになります。
フォルダ内のファイル名と配列内の JSX キーは、同様の役割を果たします。これらにより、兄弟要素の中で項目を一意に識別できます。適切に選択されたキーは、配列内の位置よりも多くの情報を提供します。並べ替えによって *位置* が変更された場合でも、key
を使用すると、React はそのライフタイムを通じて項目を識別できます。
まとめ...
このページでは、以下のことを学びました
- コンポーネントから配列やオブジェクトなどのデータ構造にデータを移動する方法。
- JavaScript の
map()
を使用して、類似したコンポーネントのセットを生成する方法。 - JavaScript の
filter()
を使用して、フィルタリングされた項目の配列を作成する方法。 - コレクション内の各コンポーネントに
key
を設定する理由と方法。これにより、React は位置やデータが変更された場合でも、各コンポーネントを追跡できます。
チャレンジに挑戦してみましょう...
チャレンジ 1/ 4: リストを2つに分割する...
この例は、すべての人物のリストを示しています。
これを変更して、**化学者**と**その他全員**の2つの別々のリストを連続して表示します。 前と同様に、person.profession === 'chemist'
をチェックすることで、人物が化学者かどうかを判断できます。
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); }