React - review 2
一、虚拟 DOM
虚拟 DOM 就是一个 Js 对象,比较 Js 对象不怎么消耗性能,比较真实 DOM 消耗性能
- 数据更新,视图重新渲染
- 第一种
- state 数据
- JSX 模板
- 数据 + 模板 结合,生成真实的DOM,来显示
- state 发生改变
- 数据 + 模板 结合,生成真实的DOM,替换原始的 DOM
缺陷:第一次生成了完整的 DOM 碎片,第二次依然生成了完整的 DOM 碎片,再用第二次的 DOM 替换第一次的 DOM,非常耗性能
- 第二种
- state 数据
- JSX 模板
- 数据 + 模板 结合,生成真实的DOM,来显示
- state 发生改变
- 数据 + 模板 结合,生成真实的DOM,并不直接替换原始的 DOM
- 新的 DOM (DoucumentFragment)和原始的 DOM 做对比,找差异
- 找出哪里发生了变化(假设 input 框发生了变化)
- 只用新的 DOM 中的 input 替换旧的 DOM 中的 input 即可
缺陷:性能的提升并不明显
- 第三种
- state 数据
- JSX 模板
- 数据 + 模板 生成虚拟DOM(虚拟 DOM 就是一个 Js 对象,用它来描述真实 DOM)=> 消耗了性能(极小)
['div', {id: 'box'}, ['span', {}, 'Hi React']
- 用虚拟 DOM 的结构生成真实的 DOM,来显示
<div id ="box"><span>Hi React</span></div>
- state 发生改变
- 数据 + 模板 结合,生成新的虚拟 DOM (极大的提升了性能)
<div id ="box"><span>Bye React</span></div>
- 比较原始虚拟 DOM 和新的虚拟 DOM 的区别, 找到区别是 span 中的内容发生了改变(极大的提升了性能)
- 直接操作 DOM ,改变 span 中的内容
二、深入了解虚拟 DOM
- render 返回的内容是 JSX 模板 JSX -> JS 对象(虚拟 DOM) -> 真实的 DOM
render() {
return (
<div>
<div><input /><button>提交</button></div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
)
}
- JSX 是如何变成 JS 对象(虚拟 DOM)的?通过 createElement
即:JSX -> createElement -> JS 对象(虚拟 DOM) -> 真实的 DOM
- Test1
class Test extends Component {
render() {
return (
<div>你好</div>
)
}
}
class Test extends Component {
render() {
return (
// <div>你好</div>
React.createElement('div', {}, '你好')
)
}
}
- Test2
class Test extends Component {
render() {
return (
<div>
<span>你好</span>
</div>
)
}
}
class Test extends Component {
render() {
return (
// <div>
// <span>你好</span>
// </div>
React.createElement('div', {}, React.createElement('span', {}, "你好"))
)
}
}
- 优点:
1)性能提升了;
2)它使得跨域应用得以实现 React Native
三、虚拟 DOM 中的 Diff 算法
- Diff => difference 寻找原始虚拟 DOM 与 新的虚拟 DOM 之间的差异
- 当数据发生改变的时候,虚拟 DOM 会进行对比,寻找差异
- 为什么 React 中的 setstate 是一个异步函数?提高 React 底层的性能
=> 当调用 setstate 时,虚拟 DOM 就要进行比对,更新页面,如果连续调用 N 次 setstate ,页面会更新 N 次。如果连续调用 N 次 setstate,React 会把它们合并成一次,只进行一次 DOM 更新 - Diff 算法
=> 原始虚拟 DOM 与 新的虚拟 DOM 同层进行比较,当发现差异时,停止比较,将原始虚拟 DOM 全部替换成新的虚拟 DOM;
=> 同层比较的算法简单,提高了比较速度 - 当数据发生改变时,比如数组:
原始数组:[a, b, c, d, e]
原始数组:[a, b, c, d, e]
=> 为什么要有 key 值呢?
没有 key 值,在进行原始数组与新的数组进行比较时,每个节点没有自己的名字,节点与节点之间的关系就很难被确立,需要用多层循环进行比较,比较麻烦且消耗性能;
有 key 值,第一次循环的时候给每个节点加上名字,第二次循环的时候直接比对是否原始数组是否有相同的名字就可以了
=> 为什么 key 值最好不要用 index,最好用 item ?
index 不稳定,当我们删除 a 的时候,新的数组变成[b, c],而 b 的下标变成了0,c 的下标变成了1;
index | 0 | 1 | 2 |
---|---|---|---|
item | a | b | c |
index | 0 | 1 |
---|---|---|
item | b | c |