如何做汽车的创意视频网站设计,房产中介网站建设进度,投资公司经营范围,响应式网站psd尺寸diffing算法
虚拟dom
我们知道#xff0c;react里面操作的都是虚拟dom#xff0c;最后经过render渲染为真正的dom#xff0c;那么为什么要提出虚拟dom这个概念呢#xff1f;其实就是将逻辑和视图区分开#xff0c;react的虚拟dom#xff0c;就相当于mvc的c#xff0c;…diffing算法
虚拟dom
我们知道react里面操作的都是虚拟dom最后经过render渲染为真正的dom那么为什么要提出虚拟dom这个概念呢其实就是将逻辑和视图区分开react的虚拟dom就相当于mvc的c将数据逻辑和真正的dom区分开我们知道对于前端来说dom操作是非常昂贵的性能消耗最大的就是dom操作。而virtual dom减少了对dom的操作,不仅避免了资源浪费而且页面的构建也得到了很大的提升。
为什么要diff
前面我们说了应避免过多的操作dom那么diff就是解决了这种问题。我们知道react在状态发生变化的时候会批量更新dom生成新的UI但是难道state的某一个值发生变化就要导致整个dom重新渲染吗这明显是不科学的为了解决这种问题react提出了diff算法通过对比新旧的两个虚拟dom树来检测那些dom是真的需要重新如安然哪些dom是没有变化的。
diff算法
传统的diff算法是通过循环递归的方式对节点一次进行对比需要O(n ^3)的时间复杂度。为什么我们从最简单的说把一棵树转换为另外一棵树其实就是把一颗n个节点的树挨个儿去另一棵n个节点的树中查找整个过程是n*n,那么如果发现有不同的地方我们就需要需改对一棵树的增删改的算法复杂度是n,那么整个过程就是n*n*n react将这种对比策略做了一个优化将复杂度降到了O(n)那么react是怎么实现的呢react的diff会预设三个限制
只进行同层级比较新旧节点的type不同直接删除旧节点创建新节点比如组件不同元素的类型不同原来是ul里面是li后来改成了divp,这个时候就会删除旧dom创建新的dom.通过key来复用节点
在上面三个限制的基础上对treeconponent,element的处理方式又做了优化
dom节点不一致直接删除旧节点创建新节点组件类型不一致直接删除组件下所有节点创建新节点同一层的dom元素以每个元素对应的key为标识提供三种操作方式删除新建和移动
diff的最小颗粒度
diff的最小颗粒度是标签我们举例看一下
class Hello extends React.Component {state{time:new Date()}componentDidMount(){this.timersetInterval((){this.setState({time:new Date()})},5000)}render() {console.log(i am render)return (ulli备注:input typetext//lilispan{this.state.time.toTimeString()}/span/li/ul)}
}我们看到每隔5秒span标签就会从新刷新一次而其他元素没有变化
key
前面我们说了同一层级的元素如果发生了变化可以删除 插入和移动前提是必须有key作为标识,如果没有key比如下面代码
class Hello extends React.Component {state {heros: [{id: 1,name: 张三},{id: 2,name: 李四}]}render() {console.log(i am render)return (ul{this.state.heros.map((hero,index){return li{hero.name}/li})}/ul)}
}
这个时候浏览器提示了一个warm ,意思是每一个child都应该有唯一key。 那么这个key应该怎么选取呢
最好使用每条数据的唯一标识作为key比如id、手机号、身份证号、学号等唯一值。如果确定只是简单的展示数据用index也是可以的。 但是不推荐。 为什么不推荐index作为key官方文档说如果列表项目的顺序可能会变化我们不建议使用索引来用作 key 值因为这样做会导致性能变差还可能引起组件状态的问题。
我们来举个例子对比一下再分析问题所在。这段代码里我点击添加按钮的时候改变了原来数组对象的顺序在数组的前头添加了一个对象我们点击看一下效果
class Hello extends React.Component {state {heros: [{id: 1,name: 张三},{id: 2,name: 李四}]}addHero(){this.setState({heros: [{id: 3,name: 王五},...this.state.heros]})}render() {console.log(i am render)return (ulbutton onClick{this.addHero}点击添加王五/buttonh1index as key/h1{this.state.heros.map((hero,index){return li key{index}{hero.name}input typetext //li})}h1age as key/h1{this.state.heros.map((hero,index){return li key{hero.id}{hero.name}input typetext //li})}/ul)}
} 我们发现了什么以index做为keyinput框并没有跟着往下移动id作为key的往下移动了我们发现问题了那么为什么index作为keyinput框不往下移动呢就是因为数据的顺序发生变化了王五被塞进了数组对象的头部但是diff的时候由于元素的key是index还是从0开始的并没有发生变化所以input框并不会移动。