React笔记(二)
1.虚拟DOM
- 虚拟DOM即虚拟节点,是
React
利用JSX将JS的Object
对象模拟成一个DOM内真实节点对象,并使用render
方法渲染到页面上。在React中文官网Virtual DOM 及内核 – React (reactjs.org)中将其称为一种概念,一种UI会以理想化的,虚拟的表现形式保存于内存之中。数据结构上虚拟DOM与真实DOM相同,均是一棵树。
2.Diff算法
- 传统的Diff算法,也就是通过一颗树以最小步数构建另一颗树时需要O(n3)的事件复杂度,因为整体可以看作两步,第一步通过动态规划将新树与旧树排列成相同的节点顺序,时间复杂度为O(n2);第二步编辑树时需要递归遍历,因此时间复杂度为O(n)。
- 但React为了减少页面渲染的时间复杂度,使用了更为先进的Diffing算法。整体流程为以下步骤
- 当状态内的数据发生变化时,React会根据新数据生成新的虚拟DOM,随后React进行新的虚拟DOM与旧的虚拟DOM树的diff比较
- 当旧虚拟DOM树中找到了与新虚拟DOM相同key时:
- 如果虚拟DOM中的内容没有变化,就直接使用之前的真实DOM
- 如果虚拟DOM中的内容有变化,就生成新的虚拟DOM,随后替换掉页面中的之前的真实DOM
- 如果旧虚拟DOM树中未找到与新虚拟DOM相同的key:
- 根据数据创建新的真实DOM,随后渲染到页面上
- 当旧虚拟DOM树中找到了与新虚拟DOM相同key时:
- 当状态内的数据发生变化时,React会根据新数据生成新的虚拟DOM,随后React进行新的虚拟DOM与旧的虚拟DOM树的diff比较
- 在启用Diff算法后,系统根据先序深度优先遍历两颗树所比较出来的差异,会作为一个批次传递给UI,UI会根据这一批的更新对真实DOM进行更新,提高性能。
3.Key
-
key
在Diff算法中起到了唯一标识的作用,所以建议使用数据的唯一标识符,例如ID等。当出现循环遍历时不建议使用index
作为key
。因为如果在循环遍历中,存在逆序增加(即从前向后添加数据),逆序删除等破坏原有顺序的操作时,会产生一些没有必要的真实DOM更新。理由如上方Diff算法所示,由于破坏原有顺序,所有index
对应的内容都发生了变化,因此导致所有的虚拟DOM都需要生成新的并对页面上的进行替换。并且当其中存在有输出类型的元素时,其也会导致刷新错误。class Demo extends Component { constructor(props){ super(props); } state = { people:[ {name:'小张',id:1}, {name:'小李',id:2}, ] }; addPerson = ()=>{ var prePeople = this.state.people; this.setState({people:[{name:'小王',id:3},...prePeople]}); } render() { var {people} = this.state; return ( <div> {people.map((element,index) => { return <div key={index}>{element.name}<input type="checkbox"/> </div> })} <button onClick={this.addPerson}>点我添加小王</button> </div> ) } }
在这个例子中使用了
index
作为key
,当在页面选择小张后的checkbox
后,点击添加小王,会使得小王的后面的checkbox
成为被选中状态,而小张后的checkbox
不是选中状态。但是将key
的index
替换为element.id
就不会出现这个问题了。
参考文章