リストのレンダリング
データのコレクションから、複数の類似したコンポーネントを表示したいことがよくあります。JavaScriptの配列メソッドを使用してデータの配列を操作できます。このページでは、filter()とmap()をReactと共に使用して、データの配列をフィルタリングし、コンポーネントの配列に変換する方法を学びます。
学習内容
- JavaScriptのを使用して配列からコンポーネントをレンダリングする方法
map() - JavaScriptのを使用して特定のコンポーネントのみをレンダリングする方法
filter() - Reactのキーをいつ、なぜ使用するか
配列からのデータレンダリング
コンテンツのリストがあるとします。
これらのリスト項目の唯一の違いは、その内容、つまりデータです。インターフェースを構築する際には、コメントのリストからプロフィール画像のギャラリーまで、異なるデータを使用して同じコンポーネントの複数のインスタンスを表示する必要がよくあります。このような場合、そのデータをJavaScriptオブジェクトや配列に格納し、map()やfilter()のようなメソッドを使用して、それらからコンポーネントのリストをレンダリングできます。
以下は、配列からアイテムのリストを生成する短い例です:
- データを配列に移動します:
- peopleメンバーをJSXノードの新しい配列
listItemsにマップします:
- コンポーネントから
listItemsを<ul>でラップして返します:
結果は次のとおりです:
上記のサンドボックスにはコンソールエラーが表示されています:
コンソール
警告: リスト内の各子には一意の「key」プロパティが必要です。
このエラーの修正方法は、このページの後半で学びます。それ以前に、データに構造を追加しましょう。
アイテムの配列のフィルタリング
このデータはさらに構造化できます。
職業が'chemist'の人だけを表示する方法が必要だとします。JavaScriptのfilter()メソッドを使用して、それらの人だけを返すことができます。このメソッドはアイテムの配列を取り、「テスト」(trueまたはfalseを返す関数)を通してそれらを渡し、テストに合格した(trueを返した)アイテムのみの新しい配列を返します。
職業(profession)が'chemist'であるアイテムだけが必要です。このための「テスト」関数は(person) => person.profession === 'chemist'のようになります。組み立て方は次のとおりです
- 作成する:
peopleに対してfilter()を呼び出し、personでフィルタリングして、化学者だけの新しい配列chemistsを作成します:
- 次に、マップする:
chemistsに対してマップします:
- 最後に、返す:コンポーネントから
listItemsを返します:
落とし穴
アロー関数は、=>の直後の式を暗黙的に返すため、return文は必要ありませんでした:
ただし、もし=>の後に{(中括弧)が続く場合は、明示的にreturnを書く必要があります!
=> {を含むアロー関数は、「ブロック本体」を持つと言われます。これにより複数行のコードを書くことができますが、必ずreturn文を自分で書く必要があります。忘れると、何も返されません!
リスト項目をkeyで順序を保つ
上記のすべてのサンドボックスで、コンソールにエラーが表示されていることに注意してください:
コンソール
警告: リスト内の各子要素には一意の "key" prop が必要です。
各配列アイテムにkey(その配列内の他のアイテムの中で一意に識別する文字列または数値)を与える必要があります:
補足
map()呼び出し内に直接記述されたJSX要素には、常にkeyが必要です!
keyは、各コンポーネントがどの配列アイテムに対応するかをReactに伝え、後でそれらを照合できるようにします。これは、配列アイテムが移動(例:ソートによる)、挿入、削除される可能性がある場合に重要になります。適切に選択されたkeyは、Reactが何が起こったかを推測し、DOMツリーに正しい更新を加えるのに役立ちます。
keyをその場で生成するのではなく、データに含めるべきです:
キーをどこから取得するか
データのソースが異なれば、キーのソースも異なります:
- データベースからのデータ:データがデータベースから来る場合、本質的に一意であるデータベースのキー/IDを使用できます。
- ローカルで生成されたデータ:データがローカルで生成され永続化される場合(例:メモ帳アプリのメモ)、インクリメントカウンター、crypto.randomUUID()、またはuuidのようなパッケージを使用して項目を作成する際にキーを生成します。
キーのルール
- キーは兄弟間で一意でなければなりません。 ただし、異なる配列内のJSXノードに対して同じキーを使用することは問題ありません。
- キーは変更してはなりません。変更するとその目的が損なわれます!レンダリング中にキーを生成しないでください。
なぜReactはキーを必要とするのか?
デスクトップ上のファイルに名前がなかったと想像してみてください。代わりに、順番で参照することになります — 最初のファイル、2番目のファイル、といった具合です。慣れることはできるかもしれませんが、一度ファイルを削除すると混乱が生じます。2番目のファイルが最初のファイルになり、3番目のファイルが2番目のファイルになる、といった具合です。
フォルダ内のファイル名と配列内のJSXキーは同様の目的を果たします。これらにより、兄弟間で項目を一意に識別できます。適切に選択されたキーは、配列内の位置よりも多くの情報を提供します。並べ替えによって位置が変化しても、keyにより、Reactはその項目のライフタイムを通じて識別できます。
落とし穴
配列内の項目のインデックスをキーとして使用したくなるかもしれません。実際、キーを指定しない場合、Reactはインデックスを使用します。しかし、項目が挿入、削除、または配列が並べ替えられると、項目をレンダリングする順序は時間とともに変化します。インデックスをキーとして使用すると、微妙でわかりにくいバグが発生することがよくあります。
同様に、key={Math.random()}のように、その場でキーを生成しないでください。これにより、レンダリング間でキーが一致しなくなり、すべてのコンポーネントとDOMが毎回再作成されることになります。これは遅いだけでなく、リスト項目内のユーザー入力も失われます。代わりに、データに基づいた安定したIDを使用してください。
コンポーネントはkeyをプロップとして受け取らないことに注意してください。これはReact自体によってヒントとしてのみ使用されます。コンポーネントがIDを必要とする場合は、別のプロップとして渡す必要があります:<Profile key={id} userId={id} />。
まとめ
このページでは以下のことを学びました:
- コンポーネントからデータを移動し、配列やオブジェクトなどのデータ構造に格納する方法。
- JavaScriptの
map()を使用して類似のコンポーネントのセットを生成する方法。 - JavaScriptの
filter()を使用してフィルタリングされたアイテムの配列を作成する方法。 - コレクション内の各コンポーネントに
keyを設定する理由と方法。これにより、位置やデータが変更されてもReactが各コンポーネントを追跡できるようになります。
Try out some challenges
Challenge 1 of 4:Splitting a list in two #
This example shows a list of all people.
Change it to show two separate lists one after another: Chemists and Everyone Else. Like previously, you can determine whether a person is a chemist by checking if person.profession === 'chemist'.
