key
我遇见的问题
在写项目的时候,项目中需要用到音频播放器,但是原始的 audio
标签在不同的浏览器,会有不同的样式,所以就自己写了一个简单的播放器,用于满足项目中播放音频的功能。
但是在使用的过程中,发现了两个问题:
- 音频出错的时候怎么提示用户;
- 在新的音频出现之后,音频组件的状态并没有重置。如下图所示:
第一张图片是查询条件改变后,audio
组件应有的状态和样式,现实确实图二的样子。
解决第一个问题
面对这个问题,我开始的时候是在组件中,给 audio
添加监听 error
事件,因为音频比较多,这样在数据查询条件改变的时候,就要频繁的操作真的DOM,性能比较差,后来发现其实可以在音频播放的时候 catch
错误,提示用户。
const playPromise = audio.play();
if (playPromise) {
playPromise.then(() => {}).catch(() => {
message.error('音频出错了');
});
}
解决第二个问题
面对这个问题,想到的就是这个组件并没有卸载重新渲染,而是改变了数据,导致的。
我们知道了问题所在,这样解决起来应该就好很多了。
嗯,我们用 React
的 key
属性来解决这个问题。
那就先来说一下 key
的作用吧:
key
的作用:
react
中的 key
属性,它是一个特殊的属性,它是出现不是给开发者用的,而是给 react
自己用的。
react
利用 key
来识别组件,它是一种身份标识。每个 key
对应一个组件,相同的 key
,react
认为是同一个组件,这样后续相同 key
对应的组件都不会被创建,而是会被传入新的数据,更新组件。
有了 key
属性后,就可以与组件建立了一种对应关系,react
根据 key
来决定是销毁重新创建组件还是更新组件。
-
key
相同,若组件属性有所变化,则react
只更新组件对应的属性;没有变化则不更新。 -
key
值不同,则react
先销毁该组件(有状态组件的componentWillUnmount会执行
),然后重新创建该组件(有状态组件的constructor和componentWillUnmount都会执行
)。
key
的使用场景
- 在项目开发中,
key
属性的使用场景最多的还是由数组动态创建的子组件的情况,需要为每个子组件添加唯一的key
属性值(最好不要用数字的index
属性 )。那么,为何由数组动态创建的组件必须要用到key
属性呢?这跟数组元素的动态性有关。
非数组动态创建的自组件,为什么不需要key
呢?因为非数组动态创建的自组件,不管state
和props
怎么变化,其所在的位置都不会发生变化,这是它天然的key
。而由数组创建的组件可能由于动态的操作导致重新渲染时,子组件的位置发生了变化。
可以看出,数组创建子组件的位置并不固定,动态改变的;这样有了key
属性后,react
就可以根据key
值来判断是否为同一组件。 - 为一个有复杂繁琐逻辑的组件添加
key
后,后续操作可以改变该组件的key
属性值,从而达到先销毁之前的组件,再重新创建该组件。
key
其他的注意事项
当然除了为数据元素生成的组件要添加 key
,且 key
要稳定且唯一之外,还需要注意以下几点:
-
key
属性是添加到自定义的子组件上,而不是子组件内部的顶层的组件上。 -
key
值的唯一是有范围的,即在数组生成的同级同类型的组件上要保持唯一,而不是所有组件的key
都要保持唯一。 - 不仅仅在数组生成组件上,其他地方也可以使用
key
,主要是react利用key
来区分组件的,相同的key
表示同一个组件,react
不会重新销毁创建组件实例,只可能更新;key
不同,react
会销毁已有的组件实例,重新创建组件新的实例。
解决问题,给组件添加 key
属性,如下:
<AudioPlay key={item.requestId} item={item} src={src} type="ASR" idNum={item.id} id={`ASRplay${item.id}`} />