1 Diffing算法
React维护了一个虚拟DOM,在页面渲染时,React会把虚拟DOM中的每个标签和真实DOM进行比较,有变化才更新,没变化不更新,这就是React中的Diffing算法。下面我们写一个简单的示例演示Diffing。
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>hello_react</title></head>
<body>
<div id="test1"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转换为js-->
<script type="text/javascript" src="../js/babel.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel"> /*此处一定要写babel*/
class Time extends React.Component {
state = {date:new Date()}
componentDidMount() {
setInterval(() => {
this.setState({date:new Date()})
}, 1000)
}
render() {
return (
<div>
<h1>hello</h1>
<input type='text'/>
<span>现在是:{this.state.date.toTimeString()}</span>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Time/>, document.getElementById('test1'))
</script>
</body>
</html>
我们会看到页面上的时间一直在更新,而我们在输入框中输入内容,如果输入框这个标签有更新的话,其内容必将消失,但是我们看到的是输入框中的内容一直不变,这就说明了Diffing算法确实起作用了。

2 虚拟DOM中的key
虚拟DOM中key的作用:
1)简单的说,key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用
2)详细的说:当状态数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,随后React进行【新虚拟DOM】和【旧虚拟DOM】的diff比较,比较规则如下:
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1)若虚拟DOM中内容没变,直接使用之前的真实DOM
(2)若虚拟DOM中的内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,随后渲染到页面。
下面例子分别演示了使用index索引作为key和使用id作为key的比较
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>hello_react</title></head>
<body>
<div id="test1"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转换为js-->
<script type="text/javascript" src="../js/babel.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel"> /*此处一定要写babel*/
/**
慢动作回放----使用index索引值作为key
数据:
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
初始的虚拟DOM:
<li key=0>小张---18</li>
<li key=1>小李---19</li>
更新后的数据:
<li key=3>小王---20</li>
<li key=0>小张---18</li>
<li key=1>小李---19</li>
更新树后的虚拟DOM:
<li key=0>小王---20</li>
<li key=1>小张---18</li>
<li key=2>小李---19</li>
------------------------------------------------------------
慢动作回放----使用id唯一标识索引值作为key
数据:
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
初始的虚拟DOM:
<li key=1>小张---18</li>
<li key=2>小李---19</li>
更新后的数据:
<li key=3>小王---20</li>
<li key=1>小张---18</li>
<li key=2>小李---19</li>
更新树后的虚拟DOM:
<li key=3>小王---20</li>
<li key=1>小张---18</li>
<li key=2>小李---19</li>
*/
class Person extends React.Component {
state = {
persons: [
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
]
}
add = ()=>{
const {persons} = this.state
const p = {id:3,name:'小王',age:20}
this.setState({persons:[p,...persons]})
}
render() {
return (
<div>
<h2>展示人员信息</h2>
<h3>使用index索引值作为key</h3>
<button onClick={this.add}>添加一个小王</button>
<ul>
{
this.state.persons.map((personObj, index)=>{
return <li key={index}>{personObj.name}---{personObj.age}</li>
})
}
</ul>
<hr/>
<hr/>
<h3>使用id(数据的唯一标识)索引值作为key</h3>
<ul>
{
this.state.persons.map((personObj)=>{
return <li key={personObj.id}>{personObj.name}---{personObj.age}</li>
})
}
</ul>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person/>, document.getElementById('test1'))
</script>
</body>
</html>
以上功能相同,但是其性能则相差很大。
有些同学说,我管他性能好坏,我实现功能就行了,这样确实没毛病,但是下面提一个新的需求,则我们不得不考虑两种方式的区别了。
我们在上面例子中<li>组件内添加一个<input>组件 <input type="text"/></li> 。然后我们做如下截图中的操作。

发现,数据错乱了。由此看出,由什么作为虚拟DOM的key还是很重要的。新旧虚拟DOM进行比较的时候,依据的就是虚拟DOM的key,如果使用了不得当的key,会带来很大的性能问题,而且有时候会发生如上图这种比较严重的数据错乱问题。
本文介绍React中的Diffing算法原理及应用,通过实例演示如何利用该算法提高页面渲染效率,并探讨虚拟DOM中key的重要性。
3236

被折叠的 条评论
为什么被折叠?



