v19.2Latest

渲染列表

你经常需要根据数据集合显示多个相似的组件。你可以使用 JavaScript 数组方法 来操作数据数组。在本页中,你将使用 filter()map()配合 React 来筛选和转换你的数据数组,将其变成一个组件数组。

你将学习
  • 如何使用 JavaScript 的 从数组渲染组件map()
  • 如何使用 JavaScript 的 仅渲染特定组件filter()
  • 何时以及为何使用 React 键(key)

从数组渲染数据

假设你有一个内容列表。

这些列表项之间的唯一区别在于它们的内容,即它们的数据。在构建界面时,你经常需要使用不同的数据来显示同一组件的多个实例:从评论列表到个人资料图片库。在这些情况下,你可以将数据存储在 JavaScript 对象和数组中,并使用map()filter() 等方法从中渲染组件列表。

以下是一个从数组生成项目列表的简短示例:

  1. 数据移入数组:
  1. people成员映射到一个新的 JSX 节点数组listItems中:
  1. listItems 组件中返回包裹在 <ul>中的内容:

结果如下:

请注意上面的沙盒显示了一个控制台错误:

控制台

警告:列表中的每个子元素都应该有一个唯一的“key”属性。

你将在本页后面学习如何修复这个错误。在此之前,我们先给你的数据添加一些结构。

筛选数组中的项目

这些数据可以进一步结构化。

假设你希望只显示职业为 'chemist'的人。你可以使用 JavaScript 的filter() 方法来仅返回这些人。该方法接收一个项目数组,将它们通过一个“测试”(一个返回 truefalse 的函数),并返回一个仅包含通过测试(返回 true)的项目的新数组。

你只需要 profession'chemist'的项目。针对此的“测试”函数看起来像(person) => person.profession === 'chemist'。以下是将其组合起来的方法:

  1. 创建一个仅包含“化学家”人员的新数组chemists,方法是在people上调用filter(),并使用 person.profession === 'chemist'进行过滤:
  1. 现在对chemists进行映射
  1. 从你的组件中返回 listItems
陷阱

箭头函数会隐式返回 =>之后的表达式,因此你不需要return 语句:

但是,如果你的 =>后面跟着一个{ 花括号,就必须显式地写出return

包含 => {的箭头函数被称为具有“块体”。它们允许你编写多行代码,但你必须自己写一个return语句。如果你忘了写,就不会返回任何内容!

使用 key 保持列表项的顺序

请注意,上面的所有沙盒都在控制台中显示了一个错误:

控制台

警告:列表中的每个子元素都应该有一个唯一的“key”属性。

你需要为每个数组项提供一个key—— 一个字符串或数字,用于在该数组中唯一标识该项:

注意

直接在 map()调用内的 JSX 元素总是需要 key!

key 告诉 React 每个组件对应数组中的哪个项,以便稍后能够匹配它们。如果你的数组项可以移动(例如由于排序)、被插入或被删除,这就变得很重要。一个精心选择的key有助于 React 推断到底发生了什么,并对 DOM 树进行正确的更新。

你应该将 key 包含在你的数据中,而不是动态生成它们:

Deep Dive
为每个列表项显示多个 DOM 节点

从何处获取你的key

不同的数据来源提供不同的 key 来源:

  • 来自数据库的数据:如果你的数据来自数据库,你可以使用数据库的键/ID,它们本质上是唯一的。
  • 本地生成的数据:如果你的数据是在本地生成并持久化的(例如笔记应用中的笔记),请使用递增计数器、crypto.randomUUID()或在创建项目时使用像uuid 这样的包。

key 的规则

  • key 在同级元素中必须是唯一的。 但是,在 不同的数组中对 JSX 节点使用相同的 key 是可以的。
  • key 不能改变,否则就失去了它们的目的!不要在渲染时生成它们。

为什么 React 需要 key?

想象一下,如果你桌面上的文件没有名称。相反,你通过它们的顺序来引用它们——第一个文件、第二个文件,依此类推。你可能会习惯这种方式,但一旦你删除了一个文件,就会变得混乱。第二个文件会变成第一个文件,第三个文件会变成第二个文件,依此类推。

文件夹中的文件名和数组中的 JSX key 有着相似的目的。它们让我们能够在同级元素中唯一地标识一个项目。一个精心选择的 key 提供的信息比数组中的位置更多。即使由于重新排序导致位置 发生变化,key也能让 React 在整个生命周期中识别出该项目。

陷阱

你可能会想使用项目在数组中的索引作为其 key。事实上,如果你没有指定 key,React 就会这么做。但是,如果插入、删除项目或数组被重新排序,你渲染项目的顺序就会随时间改变。使用索引作为 key 通常会导致微妙且令人困惑的 bug。

同样,不要动态生成 key,例如使用key={Math.random()}。这将导致 key 在每次渲染时都不匹配,从而导致你的所有组件和 DOM 每次都被重新创建。这不仅速度慢,还会丢失列表项内的任何用户输入。相反,请使用基于数据的稳定 ID。

请注意,你的组件不会将 key作为 prop 接收。它仅被 React 本身用作提示。如果你的组件需要 ID,你必须将其作为单独的 prop 传递:<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'.