0208DOM的diffing算法-React
Posted gaog2zh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0208DOM的diffing算法-React相关的知识,希望对你有一定的参考价值。
1 React DOM Diffing算法
1.1 原理
React DOM Diffing算法是React用来优化Virtual DOM更新性能的一种算法。当React中的组件状态发生变化时,React会使用Virtual DOM来进行快速的DOM更新。然而,由于Virtual DOM的渲染开销,React需要在Virtual DOM中执行一些优化策略来减少更新次数。
React的DOM Diffing算法的基本思路是比较两个不同状态的Virtual DOM树,找到最小的变化,并将其应用到实际的DOM树中。这个算法将Virtual DOM树分解成一个个的节点,并将它们逐一比较。比较过程中,React会尽可能地复用已有的DOM节点,避免重新创建DOM节点,从而减少渲染的成本。
React的DOM Diffing算法具体的实现步骤如下:
- 如果根节点不同,直接替换整个根节点。
- 如果节点类型不同,直接替换整个节点。
- 如果节点类型和key都相同,则比较节点的属性和子节点。
- 如果节点类型相同但key不同,则替换整个节点。
- 如果节点类型相同但属性不同,则更新属性。
- 如果节点类型相同但子节点不同,则递归比较子节点。
通过这些优化,React可以在保持应用程序的状态更新的同时,避免不必要的DOM操作,提高渲染性能。
1.2 测试
测试代码如下1.2-1所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1301_验证Diffing算法</title>
</head>
<body>
<div id="test"></div>
<!-- react核心库 -->
<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
<!-- 用于支持react操作DOM -->
<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<!-- 用于将jsx转为js -->
<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
/**
*
*/
class Time extends React.Component
state = date: new Date()
componentDidMount()
setInterval(() =>
// 更新状态
this.setState(date: new Date())
, 1000);
/**
* 初始化渲染,状态更新重新渲染
*/
render()
return (
<div>
<h2>hello</h2>
<input type="text"/> <br/>
<span>
现在是:this.state.date.toTimeString()
<input type="text"/> <br/>
</span>
</div>
)
// 2.渲染虚拟DOM到页面
ReactDOM.render(<Time/>, document.getElementById('test'))
</script>
</body>
</html>
测试效果如下图1.2-1所示:
2 React 中key
2.1 key的作用
在React中,key是用于帮助React识别组件中子元素的唯一标识符。当React更新组件时,React会使用key来判断哪些子元素已经发生变化,从而减少不必要的DOM操作,提高渲染性能。
具体来说,当React渲染组件时,它会生成一个Virtual DOM树。Virtual DOM是一个轻量级的JavaScript对象,用于描述实际的DOM结构。当组件的状态发生变化时,React会比较新旧Virtual DOM树之间的差异,然后将差异应用到实际的DOM树上。
在比较Virtual DOM树时,React使用key来识别哪些子元素已经发生变化。如果两个元素具有相同的key,则React会认为它们是同一个元素,并将其重用。如果两个元素的key不同,则React会将其视为两个不同的元素,并重新创建DOM节点。因此,使用正确的key可以帮助React减少DOM操作次数,提高渲染性能。
除了性能方面的考虑,key还可以帮助开发者维护组件的内部状态。在一些需要对组件进行增删操作的场景中,使用key可以确保每个子元素的状态正确地被保留和更新。
Diff对比的最小粒度上标签
2.2 key的取值
在React中,key应该是具有稳定、唯一和可预测性的值。这有助于React识别子元素并减少不必要的DOM操作,提高渲染性能。
通常情况下,key的取值有以下几种方式:
- 使用唯一ID(推荐):如果每个子元素都有唯一的ID属性,那么可以使用ID作为key的取值。这样可以确保每个子元素都有一个唯一的key。
- 使用索引:如果没有唯一ID,可以使用数组索引作为key的取值。但是,需要注意的是,如果数组中的元素顺序发生变化,那么key也会随之变化,这可能会导致不必要的DOM操作。
- 使用唯一的字符串:如果没有唯一ID和数组索引,可以使用唯一的字符串作为key的取值。可以使用UUID或其他生成唯一字符串的方法。
- 使用其他唯一属性:如果子元素具有其他唯一属性,例如用户名或电子邮件地址,可以使用这些属性作为key的取值。
需要注意的是,尽管可以使用各种方法生成key的值,但必须确保每个key都是唯一且稳定的。如果key的取值不稳定或重复,可能会导致React无法正确地识别子元素,并且可能会导致不必要的DOM操作,从而降低渲染性能。
用index作为key可能引发的问题:
- 若对数据进行: 逆序添加、逆序删除的功能破坏顺序操作:会产生没有必要的真实DOM的更新,即界面没效果,但效率低。
- 如果结构中还保护输入类DOM:会产生错误DOM更新
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅渲染列表用于展示,使用index作为key是没有问题的。
测试代码2.2-1如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1301_验证Diffing算法</title>
</head>
<body>
<div id="test"></div>
<!-- react核心库 -->
<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
<!-- 用于支持react操作DOM -->
<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<!-- 用于将jsx转为js -->
<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
/**
*
*/
class Person extends React.Component
state =
persons: [
id: 1,name: '小张', age: 22,
id: 2,name: '小王', age: 32,
]
add = () =>
const persons = this.state
const p = id: persons.length+1,name: '小丽', age: 25
this.setState(persons: [p, ...persons])
/**
* 初始化渲染,状态更新重新渲染
*/
render()
return (
<div>
<h2>展示人员信息</h2>
<button onClick=this.add>添加新成员</button>
<h3>使用index(索引)作为key</h3>
<ul>
this.state.persons.map((p,index)=>
return <li key=index>
p.name----p.age
<input type="text"/>
</li>
)
</ul>
<hr/>
<h3>使用id(数据唯一标识)作为key</h3>
<ul>
this.state.persons.map((p)=>
return <li key=p.id>
p.name----p.age
<input type="text"/>
</li>
)
</ul>
</div>
)
// 2.渲染虚拟DOM到页面
ReactDOM.render(<Person/>, document.getElementById('test'))
</script>
</body>
</html>
- index作为key逆序添加导致全部已有标签的key+1,改变;那么对比相同key时,标签内容不一致,会重新渲染。所以页面上好像没啥问题,但是效率很低。
- 如果有子元素,会导致数据错乱。
添加新元素前效果如下下2.2-1所示:
添加新成员后效果图示如下2.2-2所示:
结语
❓QQ:806797785
⭐️源代码仓库地址:https://gitee.com/gaogzhen/react-study
参考:
[1]React视频教程[CP/OL].2020-12-15.p48.
[2]React官网[CP/OL].
[2]ChatGPT[CP/OL].
以上是关于0208DOM的diffing算法-React的主要内容,如果未能解决你的问题,请参考以下文章