美文网首页
React: 组件的key

React: 组件的key

作者: VirtualX | 来源:发表于2017-11-28 00:20 被阅读0次

参考文档:
React文档:Lists and Keys
React文档:Reconciliation
React 实践心得:key 属性的原理和用法 ——淘宝前端团队

A “key” is a special string attribute you need to include when creating lists of elements.

最早在React文档中看到关于组件的key,当时并没有很在意,直到某天在控制台看到了如下报错信息:

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `App`. See https://fb.me/react-warning-keys for more information.

那么这个 key 究竟有多重要呢?

React文档中说应当在数组中给组件一个单独的 key ,React 用这个 key 作为组件的身份来识别具体对哪个组件做增删改各种操作。通常使用这个组件的唯一标识来作为key值,例如组件数据的id等:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

文档中写到,通常来说,不建议使用 index 作为 key 值。
毕竟 index 太易变,如果使用 index 作为 key,某种程度上来说就失去了使用 key 的意义,同时可能还会引发其他的问题。但是,如果你在通过遍历数组生成一组组件时没有为每个组件分配key值,React 会自动使用 index 作为 key 值来分配给每个组件

注意:

  • 关于 key 值的唯一性:

Keys used within arrays should be unique among their siblings. However they don’t need to be globally unique.

也就是说,我们可以在生成两组不同的组件时使用相同的一组 key。

  • key 只提供给 React 使用

Keys serve as a hint to React but they don’t get passed to your components.

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
)

虽然 key 在使用时看起来和 props 很像,但你并不能在组件中通过 prop 取到它的值,如上述代码,在 Post 组件中,可以取到 props.id 的值,但 props.key 的值是拿不到的。

看起来没有使用数组 map() 时,你的组件可能也需要 key

认识到 key 的重要性之后,我也曾经天真地以为只需要在 map 中使用它,毕竟React文档好像也只是在强调 map,直到上一个某一天之后不太久的某天……

这次,我遇到了一个略微复杂的需求,大概是要先 map 一个数据数组,加载一个用户列表:

const userList = users.map((user) =>
  <UserItem
    key={user.id}
    id={user.id} />
)

加载用户列表的过程当然每个 item 都需要一个
key 的,我选择用 user.id 作为 UserItem 的 key,然后在与某个 item 发生交互(例如点击)时,把 user.id 传给用户详情组件 <UserInfoCard id={user.id}/>,拿着 user.id 去redux 里查询这个用户信息数据,如果没有就去后端请求这个数据,将后端返回的数据加入redux,再从 redux 中取得数据加载到组件,每次只展示当前点击的 UserItem 对应的 UserInfoCard,但所有的 UserInfo 组件都自动渲染在某一个节点(假设为Container)下。所有 UserInfoCard 一旦 mount,在父节点 Container 未发生变化时不会 unmount,仅会 update 数据和是否可见的属性。

面对这个逻辑,作为 UserInfoCard 的使用者,我没有关心它具体渲染在哪个节点下,自然忽略了它们共有一个父节点,也就是说,虽然没有使用 map 来生成一组 UserInfo 组件,但确确实实每增加一个UserInfoCard,都等同于在它们的父节点Container下为它们增加了一个同为 UserInfoCard 的好姐妹。

这样实际上和 map 生成的一组好兄弟本质上并没有什么区别,没有 key 值的话,React 难以对它们加以区分,另外本地没有的数据还需要从后端获取,假设这样一种情况:

  1. 点击一号用户的 UserItem,需向后端请求一号用户的数据
  2. 在后端的数据返回之前,点击二号用户的 UserItem,二号用户的数据也没有,向后端请求二号用户的数据

从点击一号用户到再点击二号用户的过程,对父节点 Container 来说只是一个
Update 的过程,在点击二号用户之后,收到一号用户的数据之前,对父节点来说,此时它有两个完全一样的React子元素(两个没有数据的 UserInfoCard ),此时收到了一个用户的信息数据,那么把它更新给哪个 UserInfoCard 呢?请求数据这种异步操作无法预料哪一条请求的数据会先到达,这就很容易造成混乱了——可能你点击了二号用户的UserItem,看到的却是一号用户的信息。

为了避免这种混乱,使用 key 属性就非常有必要了。

在使用 UserInfoCard 时将 user.id 作为
key 一并传给 UserInfoCard,这样用户在点击不同的 UserItem 时,key 也发生了变化,结合前面谈到的 key 的作用,不难发现,对 React 来说此时就很容易分辨究竟是哪个 UserInfoCard 需要更新,即使多次点击同一个 UserItem,也不会创建多个相同的 UserInfoCard,而是会更新该 key 对应的 UserInfoCard 实例。

总结:不止在 map 一个数组创建一组组件实例时需要使用 key 为每个数组元素标记,几乎在任何由统一结构或同一组件实例化为一组对象时,都应使用 key 作为它们的身份识别。

参考文档里最后一篇文章提到了在拥有复杂状态(每个状态有具体与之对应的对象)的组件里使用 key 来使组件在适当的时候触发销毁和重建,以此来保持组件内部逻辑的清晰,这也是文档里没有提到的一种对 React key 的应用。

相关文章

  • React: 组件的key

    参考文档:React文档:Lists and KeysReact文档:ReconciliationReact 实践...

  • echarts图 饼图

    1 强制react组件实时刷新添加一个key 值,触发的时候,改变key值,带动组件更新 2 饼图 呈现的效果:

  • Vue动态路由缓存不相互影响的解决办法

    关于react与vue中的key 之前在学习react的时候,常常遇到循环渲染组件时会提示需要在循环组件中加上ke...

  • 问题记录-antd Table

    2019-03-29ant design Table组件关于column的key官方文档中说这个key是React...

  • React组件中的Key

    概述 React的初学者在写React项目的过程中,经常会在写一个列表组件的时候,发现控制台抛出了如下的Warni...

  • react初学概念

    React应用程序的组成部分: 元素和组件 列表 & Key 一个元素的 key 最好是这个元素...

  • react

    1、react中key的作⽤2、⽣命周期,新旧⽣命周期的不同3、函数组件和component组件的区别4、控制组件...

  • React/Vue 项目时为什么要在组件中写 key,其作用是什

    React/Vue 项目时为什么要在组件中写 key,其作用是什么? vue和react都是采用diff算法来对比...

  • 2020-03-10

    1. 写 React/Vue 项目时为什么要在组件中写 key,其作用是什么? key 的作用是为了在 diff ...

  • 高级前端程序员面试问题与答案【精选9道】

    1. 写 React/Vue 项目时为什么要在组件中写 key,其作用是什么? key 的作用是为了在 diff ...

网友评论

      本文标题:React: 组件的key

      本文链接:https://www.haomeiwen.com/subject/rupdbxtx.html