列表和Keys

在组件中渲染列表数据是非常常见的场景,例如,BBS 项目 PostList 组件就需要根据列表数据 posts 进行渲染:

class PostList extends Component {
    /** 省略其余代码 **/

  render() {
    return (
      <div className='container'>
        <h2>帖子列表</h2>
        <ul>
          {this.state.posts.map(item =>
            <PostItem
              post = {item}
              onVote = {this.handleVote}
            />
          )}
        </ul>
      </div>
    );
  }
}

下面运行 BBS 项目,然后打开 Chrome 浏览器的控制台,可以看到如图 2-5 所示的警告信息。

image 2024 04 23 09 34 27 006
Figure 1. 图2-5

警告信息提示我们,应该为列表中的每个元素添加一个名为 key 的属性。那么这个属性有什么作用呢?原来,React 使用 key 属性来标记列表中的每个元素,当列表数据发生变化时,React 就可以通过 key 知道哪些元素发生了变化,从而只重新渲染发生变化的元素,提高渲染效率。

一般使用列表数据的 ID 作为 key 值,例如可以使用帖子的 ID 作为每一个 PostItemkey

class PostList extends Component {
    /** 省略其余代码 **/

  render() {
    return (
      <div className='container'>
        <h2>帖子列表</h2>
        <ul>
          {this.state.posts.map(item =>
            <PostItem
            {/* 将id 赋值为 key 属性,作为唯一标识 */}
              key = {item.id}
              post = {item}
              onVote = {this.handleVote}
            />
          )}
        </ul>
      </div>
    );
  }
}

再次运行程序,你会发现之前的警告消息已经不存在了。本节项目源代码的目录为 /chapter-02/bbs-components-keys

如果列表包含的元素没有 ID,也可以使用元素在列表中的位置索引作为 key 值,例如:

// 省略其它
{this.state.posts.map((item,index) =>
<PostItem
  key = {index}
  post = {item}
  onVote = {this.handleVote}
/>
)}

但并不推荐使用索引作为 key,因为一旦列表中的数据发生重排,数据的索引也会发生变化,不利于 React 的渲染优化。我们还会在第 5 章中详细说明这一情况。

虽然列表元素的 key 不能重复,但这个唯一性仅限于在当前列表中,而不是全局唯一。例如在一个组件中两次使用 post.id 作为列表数据的 key

image 2024 04 23 09 55 16 083