Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >react中key的正确使用方式

react中key的正确使用方式

作者头像
ConardLi
发布于 2019-09-08 14:55:29
发布于 2019-09-08 14:55:29
2.9K00
代码可运行
举报
文章被收录于专栏:code秘密花园code秘密花园
运行总次数:0
代码可运行

key的原理?为了么要使用key?选什么做key?

在开发react程序时我们经常会遇到这样的警告,然后就会想到:哦!循环子组件忘记加key了~

出于方便,有时候会不假思索的使用循环的索引作为key,但是这样真的好吗?什么样的值才是key的最佳选择?

为了弄明白,本文将从三个方面来分析"key":

1.为什么要使用key

2.使用index做key存在的问题

3.正确的选择key

1.为什么要使用key

react官方文档是这样描述key的:

Keys可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。

react的diff算法是把key当成唯一id然后比对组件的value来确定是否需要更新的,所以如果没有key,react将不会知道该如何更新组件。

你不传key也能用是因为react检测到子组件没有key后,会默认将数组的索引作为key。

react根据key来决定是销毁重新创建组件还是更新组件,原则是:

  • key相同,组件有所变化,react会只更新组件对应变化的属性。
  • key不同,组件会销毁之前的组件,将整个组件重新渲染。

2.使用index做key存在的问题

2.1 受控组件

单纯的展示组件比如span,这些组件是受控组件,意味着他们的值将是我们给定好的。

如果子组件只是受控组件,使用index作为key,可能表面上不会有什么问题,实际上性能会受很大的影响。例如下面的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ['张三','李四','王五']=>
<ul>
   <li key="0">张三</li>
   <li key="1">李四</li>
   <li key="2">王五</li>
</ul>
// 数组重排 -> ['王五','张三','李四'] =>
<ul>
   <li key="0">王五</li>
   <li key="1">张三</li>
   <li key="2">李四</li>
</ul>

当元素数据源的顺序发生改变时,对应的:

key为0,1,2的组件都发生了变化,三个子组件都会被重新渲染。(这里的重新渲染不是销毁,因为key还在)

相反,我们使用唯一id作为key:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ['张三','李四','王五']=>
<ul>
   <li key="000">张三</li>
   <li key="111">李四</li>
   <li key="222">王五</li>
</ul>
// 数组重排 -> ['王五','张三','李四'] =>
<ul>
   <li key="222">王五</li>
   <li key="000">张三</li>
   <li key="111">李四</li>
</ul>

根据上面的更新原则,子组件的值和key均未发生变化,只是顺序发生改变,因此react只是将他们做了移动,并未重新渲染。

2.2 非受控组件

像input这样可以由用户任意改变值,不受我们控制的组件,在使用了index作为key时可能会发生问题,看如下的例子:

子组件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  render() {    return (      <div>
       <p >值:{this.props.value}</p>
       <input />
     </div>
   );
 }
}

父组件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
this.state.data.map((element, index) => {
   return <Child value={element} key={index} />
   })
}

我们在前两个输入框分别输入对应的值:

然后在头部添加一个元素:

很明显,这个结果并不符合我们的预期,我们来分析一下发生了什么:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div key="0">
   <p >值:0</p>
   <input />
</div>
<div key="1">
   <p >值:1</p>
   <input />
</div>
<div key="2">
   <p >值:2</p>
   <input />
</div>

变化后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div key="0">
   <p >值:5</p>
   <input />
</div>
<div key="1">
   <p >值:0</p>
   <input />
</div>
<div key="2">
   <p >值:1</p>
   <input />
</div>
<div key="3">
   <p >值:2</p>
   <input />
</div>

可以发现:key 0,1,2并没有发生改变,根据规则,不会卸载组件,只会更新改变的属性。

react只diff到了p标签内值的变化,而input框中的值并未发生改变,因此不会重新渲染,只更新的p标签的值。

当使用唯一id作为key后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div key="000">
   <p >值:0</p>
   <input />
</div>
<div key="111">
   <p >值:1</p>
   <input />
</div>
<div key="222">
   <p >值:2</p>
   <input />
</div>

变化后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div key="555">
   <p >值:5</p>
   <input />
</div>
<div key="000">
   <p >值:0</p>
   <input />
</div>
<div key="111">
   <p >值:1</p>
   <input />
</div>
<div key="222">
   <p >值:2</p>
   <input />
</div>

可以很明显的发现:key为 111,222,333的组件没有发生任何改变,react不会更新他们,只是新插入了子组件555,并改变了其他组件的位置。

3.正确的选择key

3.1 纯展示

如果组件单纯的用于展示,不会发生其他变更,那么使用index或者其他任何不相同的值作为key是没有任何问题的,因为不会发生diff,就不会用到key。

3.2 推荐使用index的情况

并不是任何情况使用index作为key会有缺陷,比如如下情况:

你要分页渲染一个列表,每次点击翻页会重新渲染:

使用唯一id:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
第一页<ul>
   <li key="000">张三</li>
   <li key="111">李四</li>
   <li key="222">王五</li>
</ul>第二页<ul>
   <li key="333">张三三</li>
   <li key="444">李四四</li>
   <li key="555">王五五</li>
</ul>

翻页后,三条记录的key和组件都发生了改变,因此三个子组件都会被卸载然后重新渲染。

使用index:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
第一页<ul>
   <li key="0">张三</li>
   <li key="1">李四</li>
   <li key="2">王五</li>
</ul>第二页<ul>
   <li key="0">张三三</li>
   <li key="1">李四四</li>
   <li key="2">王五五</li>
</ul>

翻页后,key不变,子组件值发生改变,组件并不会被卸载,只发生更新。

3.3 子组件可能发生变更/使用了非受控组件

大多数情况下,使用唯一id作为子组件的key是不会有任何问题的。

这个id一定要是唯一,并且稳定的,意思是这条记录对应的id一定是独一无二的,并且永远不会发生改变。

不推荐使用math.random或者其他的第三方库来生成唯一值作为key。

因为当数据变更后,相同的数据的key也有可能会发生变化,从而重新渲染,引起不必要的性能浪费。

如果数据源不满足我们这样的需求,我们可以在渲染之前为数据源手动添加唯一id,而不是在渲染时添加。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 code秘密花园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
react中key的作用是什么
key这个属性一般是在输出循环列表时,react要求我们填写的一个属性,如果不填的话,在控制台会给出警告,当然页面渲染也是可以正常渲染的,但是可能会引发一些不确定的bug,所以我们在写循环列表输出时还是建议将key这个属性带上。
OECOM
2020/07/02
1.8K0
react中key的作用是什么
关于React的Key导致的bug总结
因为本身数据没有类似id的唯一值,这里便不假思索的启用了索性作为key,渲染也就完成了,顺便也加上了添加和删除功能,一切都是那么顺利。因为需要编辑,这里及把最初的展示组件替换成了input组件,这里并没有使用受控组件,而使用非受控组件,监听blur后再进行数据更新上传至服务器,所以input只设置了defaultvalue值,然后测试,发现删除怎么也删不了第一行。如图所示:
gary12138
2022/10/05
7140
关于React的Key导致的bug总结
Vue中v-for引发key的原理
打不着的大喇叭
2024/03/11
1170
Vue中v-for引发key的原理
react进阶用法完全指南
React调用回调函数,正确设置this指向的三种方法 通过bind this.increment = this.increment.bind(this); 通过箭头函数 <button onClick={this.multi}>点我*10</button> multi = () => { this.setState({ count: this.state.count * 10 }) } 箭头函数包裹 <button onClick={() => {this.muti2(
xiaofeng123aa
2022/09/26
6K0
在 Vue 中为什么不推荐用 index 做 key
本文首发于政采云前端团队博客:在 Vue 中为什么不推荐用 index 做 key https://zoo.team/article/vue-index
政采云前端团队
2021/11/12
1.4K0
JSX
React是用于构建用户界面的JavaScript库, 核心专注于视图,目的实现组件化开发。
用户4793865
2023/01/12
7870
JSX
React入门看这篇就够了
React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。
random_wang
2019/09/11
4.7K0
react学习
JSX是一个JavaScript的语法扩展。因为JSX在语法上更简洁JavaScript而不是HTML,所以React DOM使用cameCase来定义属性的名称,而不是用HTML属性名称的命名约定。
Cloud-Cloudys
2020/07/07
4.4K0
「react进阶」年终送给react开发者的八条优化建议
笔者是一个 react 重度爱好者,在工作之余,也看了不少的 react 文章, 写了很多 react 项目 ,接下来笔者讨论一下 React 性能优化的主要方向和一些工作中的小技巧。送人玫瑰,手留余香,阅读的朋友可以给笔者点赞,关注一波 。陆续更新前端文章。
用户6835371
2021/06/01
1.9K0
「react进阶」年终送给react开发者的八条优化建议
React 状态、事件与动态渲染
例子中使用map方法将每个元素的值*2,最后得到的数组为:[2, 4, 6, 8, 10]。在React中,处理组件数组的方式与之类似。
随风溜达的向日葵
2018/07/31
1.5K0
[边学边练]用简单实例学习React
学习之路不可停止,最近在玩 React。也动手尝试写了一个实例。借此整理总结下初步学习 React 的一些基础知识。因为这几天比较忙,没那么多时间,所以实例和文章没有很细致。如果大家发现文章有错误的地方,请多谅解。有什么更新的建议,欢迎在评论区指出。该文章主要是大概讲下和快速上手使用,如果深入,要靠自己探索,后期我也会补充文章。
守候i
2018/08/27
1.3K0
[边学边练]用简单实例学习React
常见react面试题(持续更新中)
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>、<group>、<div> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。
beifeng1996
2022/12/16
2.7K0
react面试题
调用setState之后发生了什么? 在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。 扩展1: setState的第一个参数除了对象,还能传什么? ---函数,参数为当前state
用户7162790
2022/03/23
7240
React面试:谈谈虚拟DOM,Diff算法与Key机制
原生的JS DOM操作非常消耗性能,而React把真实原生JS DOM转换成了JavaScript对象。这就是虚拟Dom(Virtual Dom)
beifeng1996
2022/10/01
1.5K0
React学习笔记(三)—— 组件高级
下面了的代码,我们用到了数组函数的map方法来实现数组的每一个值变成它的2倍,同时返回一个新数组,最后打印出了这个数组:
张果
2023/03/11
8.4K0
React学习笔记(三)—— 组件高级
13. Vue v-for指令的使用方式以及使用key解决组件问题
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
Devops海洋的渔夫
2020/03/19
2K0
react入门(五):事件处理、条件渲染、列表&keys、表单
一、事件处理 React事件绑定属性的命名采用驼峰式写法,而不是小写。 直接看代码 两种方式绑定事件并传参数 第一种: constructor(props) { super(props); //在dom上用bind函数绑定了this,这里可以省略 this.handleClick = this.handleClick.bind(this); } handleClick(value, e) { //e要写在value后面 console.log(value);
柴小智
2020/02/13
1.1K0
【React】学习笔记(一)——React入门、面向组件编程、函数柯里化
用于构建用户界面的 Javascript 库,它主要专注于界面与视图。采用组件化模式、声明式编码,提高开发效率及组件复用率。在React Native中可以使用React语法进行移动端开发。使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互。
鸡先生
2022/10/29
5.2K0
【React】学习笔记(一)——React入门、面向组件编程、函数柯里化
前端一面常考react面试题
相同点: 组件是 React 可复用的最小代码片段,它们会返回要在页面中渲染的 React 元素。也正因为组件是 React 的最小编码单位,所以无论是函数组件还是类组件,在使用方式和最终呈现效果上都是完全一致的。
beifeng1996
2023/01/05
1.2K0
是时候该知道React中的Key属性的作用与最佳实践了!
在React中,我们常常会遇到需要渲染列表或循环生成组件的场景。为了提高性能和优化用户体验,React引入了一个特殊的属性——key。本文将详细介绍React中key属性的作用、原理,并提供一些最佳实践。
用户6297767
2024/01/14
1.4K0
是时候该知道React中的Key属性的作用与最佳实践了!
相关推荐
react中key的作用是什么
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验