1.旧的虚拟dom和新的虚拟dom对比,首先看他们的key是否相同
2.相同继续对比他们的内容,不同生成新的真实dom进行替换
3.如果内容和key都相同,复用旧的真实dom 不做改变
那么如果我们使用遍历时候自动生成的index作为每个节点的key可能会出现什么问题呢? 下面放个小案例
首先,初始时我们进行遍历persons
他会是这样一个过程,源数据
1.persons: [
{ id: 1, name: “张三”, age: 15 },
{ id: 2, name: “李四”, age: 16 },
],
生成的真实dom节点
< ul>
< li key= "0" > 张三-- 15 < / li>
< li key= "1" > 李四-- 16 < / li>
< / ul>
然后我们在这个名单前面插入一个{id:3,name:‘王五’,age:14}的数据会变成这样子
< ul>
< li key= "0" > 王五-- 14 < / li>
< li key= "1" > 张三-- 15 < / li>
< li key= "2" > 李四-- 16 < / li>
< / ul>
通过上面的更新可以发现 王五将之前张三的key给占用了
也就是说当我进行更新这一过程首先新的虚拟dom
<li key="0">王五--14</li>
和旧的虚拟dom
< li key= "0" > 张三-- 15 < / li>
进行比较 新的dom先比较key两人相同,在比较内容一个是王五–14 一个是张三15 ,内容发生变化了,这时就会进行使用新的虚拟dom生成新的真是dom重新渲染页面,而且不仅是之前的张三受影响需要重新生成,后面的李四也要被张三进行替换在生成一个新的内容为张三的真实dom,这样就会导致所有的dom都要重新生成重新渲染,导致性能下降
< ! DOCTYPE html>
< html lang= "en" >
< head>
< meta charset= "UTF-8" / >
< meta http- equiv= "X-UA-Compatible" content= "IE=edge" / >
< meta name= "viewport" content= "width=device-width, initial-scale=1.0" / >
< title> Document< / title>
< / head>
< body>
< script src= "https://unpkg.com/react @16/umd/react .development.js" > < / script>
< script src= "https://unpkg.com/react -dom@16/umd/react -dom.development.js" > < / script>
< script src= "https://unpkg.com/babel-standalone@6.26.0/babel.js" > < / script>
< div id= "root" > < / div>
< script type= "text/babel" >
let root = document. getElementById ( "root" ) ;
class App extends React. Component {
constructor ( props ) {
super ( props) ;
}
state = {
persons: [
{ id: 1 , name: "张三" , age: 15 } ,
{ id: 2 , name: "李四" , age: 16 } ,
] ,
} ;
handle = ( ) => {
const { persons } = this . state;
const p = {
id: 0 ,
name: "王五" ,
age: 14 ,
} ;
this . setState ( {
persons: [ p, ... persons] ,
} ) ;
} ;
render ( ) {
return (
< div>
< button onClick= { this . handle} > 点击添加< / button>
< ul>
{ this . state. persons. map ( ( person, index ) => (
< li key= { index} >
{ person. name} -- { person. age}
< / li>
) ) }
< / ul>
< / div>
) ;
}
}
ReactDOM. render ( < App name= "hell" / > , root) ;
< / script>
< / body>
< / html>
试想一下经过上面的推导致,如果我们使用id作为唯一的key值会怎么样呢
更新前
< ul>
< li key= "1" > 张三-- 15 < / li>
< li key= "2" > 李四-- 16 < / li>
< / ul>
更新后
< ul>
< li key= "0" > 王五-- 14 < / li>
< li key= "1" > 张三-- 15 < / li>
< li key= "2" > 李四-- 16 < / li>
< / ul>
这次 虽然王五插入的还是张三的前面但是只对比了一次 王五和上面是否有一样的key=0的节点 ,没有生成新的真实dom进行渲染,而张三和上面key=1的进行对比,发现上面有一个key=1的节点,然后再对比他们的内容是否相同,发现内容也相同,那么就可以复用旧的真实dom,节约性能