现象描述:添加小王在第一个元素,在li元素可以看出来,但是在后面的输入框小张的位置占用了。因为添加小王在第一个元素,它的key是0,旧的dom的key=0是小张。所以校长被顶上去了。看到这个现象特意去学了react虚拟dom的diff算法。
diif算法虚拟dom的更新过程:
1.旧的虚拟dom的key寻找新的dom相同的key;
2.找到相同的key,内容有变化,就更新该位置的内容
3.找到相同的key,内容没有变化,该位置的内容不变
4.若找不到,则更新真实的dom.
用index作为key,对表格进行增删查改,序号会更新排序,也就是新元素的长度多少,就会更新多少次的真实dom。这样无疑效率变低。
那么,一定用key?不用可以吗?
当不带Key的时候,采用的是遍历的方式来对比新旧节点,从而达到更新节点的效果。组件react不知道某个节点是否移动了。
当索引位置发生变化,元素的类型不同,就要重新销毁树重建,效率太地下。但是,在动态的增删中,列表渲染通常都是相同的类型,触发了列表渲染通常都是相同的类型,所以位置变动时,多半是会触发节点原地复用效果,不会导致树的销毁重建发生。只是有一点:这个节点有自己的内部状态,最经典的莫过于输入框。
原因是 React 做了原地复用,而 input 没有传 props,不需要打 props 补丁,保持了原样
(我原来用index作为key,也会出现这个情况,具体什么原因有待研究)
带key的时候使用的是map映射来更新节点。
在模板简单的时候使用就地复用(就是不使用key)效率会更高。没有key的情况下可以对节点就地复用,提高性能。
但是只适用于不依赖子组件状态(没有和data绑定,例如,
{{data}}
,这个是个人理解,正确性待验证)或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。所以使用key并不意味着一定可以提高diff算法的效率。
key的作用主要是为每个节点设置一个唯一的标识,可以更快,更准确的拿到节点。
在一些情况下,还可以避免就地复用带来的副作用(表单数据错位)
表单错位的原因:
用索引作为key时,新的虚拟dom和旧的虚拟dom,key相同,组件类型也相同,就会复用组件,所以就会出现表单数据错位的现象。用id作为key,那就会重新生成一个组件,就不会出现上述问题
参考文档:https://blog.csdn.net/fe_watermelon/article/details/125550099