React DOM Diffing与 Key(三)
React 官网链接:
接着上节 React 组件生命周期与三大属性state、refs、props(二)
DOM Diffing 算法
调用 setState() 方法进行组件更新的时候, 是一种合并,不是替换,这也是React高效的原因之一~,如图:
setState() 更新状态:
- 重新创建虚拟DOM
- 新旧节点比较
- 若新旧节点相同,则不更新
- 若新旧节点差异,则进行更新
- 局部页面重绘
Key
虚拟 DOM 中 key 是虚拟DOM对象的标识,在更新显示时用 key 来判断
详细的说:当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的 diff比较,比较规则如下:
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 若虚拟DOM中内容没变, 直接使用之前的真实DOM
- 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
- 旧虚拟DOM中未找到与新虚拟DOM相同的key:
- 根据数据创建新的真实DOM,随后渲染到到页面
总之:在进行 DOM Diffing 比较的时候,Key 起着关键的作用
有以下这个情形:(列表数据进行DOM Diffing,利用什么作为Key?)
1、使用index索引值作为key
初始数据:
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
初始的虚拟DOM:
<li key=0>小张---18<input type="text"/></li>
<li key=1>小李---19<input type="text"/></li>
更新后的数据:(将数据插入到第一条)
{id:3,name:'小王',age:20},
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
更新数据后的虚拟DOM:(index都会变了,那么key判断就三条数据都会更新)
<li key=0>小王---20<input type="text"/></li>
<li key=1>小张---18<input type="text"/></li>
<li key=2>小李---19<input type="text"/></li>
那么用index作为key可能会引发的问题:
-
若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
-
如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题
-
注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
仅用于渲染列表用于展示,使用index作为key是没有问题的。
2、使用数据唯一 id 作为key
初始数据:
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
初始的虚拟DOM:
<li key=1>小张---18<input type="text"/></li>
<li key=2>小李---19<input type="text"/></li>
更新后的数据:
{id:3,name:'小王',age:20},
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
更新数据后的虚拟DOM:(key不变,那么就只会更新新数据)
<li key=3>小王---20<input type="text"/></li>
<li key=1>小张---18<input type="text"/></li>
<li key=2>小李---19<input type="text"/></li>
开发中如何选择key?:
- 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
- 如果确定只是简单的展示数据,用index也是可以的。