面试题答案
一键面试虚拟DOM diff算法在列表渲染场景下的工作原理
- 整体流程:React在进行列表渲染时,会首先创建虚拟DOM树。当数据发生变化,会生成新的虚拟DOM树,然后通过diff算法对新旧两棵虚拟DOM树进行对比,找出差异并应用到真实DOM上。
- 列表项增加:
- diff算法在对比新旧虚拟DOM列表时,若发现新列表比旧列表多出了某些项,会在真实DOM中创建对应的新节点并插入到正确位置。
- 例如,旧列表为
[<li key="1">Item 1</li>]
,新列表为[<li key="1">Item 1</li>, <li key="2">Item 2</li>]
,diff算法会检测到key
为2
的新列表项,然后在真实DOM中创建<li>Item 2</li>
并插入到Item 1
之后。
- 列表项删除:
- 当新列表比旧列表少了某些项时,diff算法会在真实DOM中找到对应节点并删除。
- 比如,旧列表为
[<li key="1">Item 1</li>, <li key="2">Item 2</li>]
,新列表为[<li key="1">Item 1</li>]
,diff算法会检测到key
为2
的列表项被删除,从而在真实DOM中删除<li>Item 2</li>
。
- 列表项移动:
- React依赖
key
来识别列表项。当列表项顺序变化时,若key
不变,diff算法能识别出是移动操作。 - 例如,旧列表为
[<li key="1">Item 1</li>, <li key="2">Item 2</li>]
,新列表为[<li key="2">Item 2</li>, <li key="1">Item 1</li>]
,diff算法通过key
识别出两项位置交换,然后在真实DOM中调整两项顺序。
- React依赖
批量更新策略原理
- 原理:在React中,批量更新策略是指当一个事件处理函数或者生命周期函数中多次调用
setState
时,React不会立即更新DOM,而是将这些更新操作合并,批量处理后一次性更新DOM。这样可以减少DOM操作次数,提高性能。 - 源码层面分析:在React源码中,
setState
函数会将新的状态加入到一个更新队列中。例如,在ReactFiberClassComponent.js
中,enqueueSetState
函数负责将更新操作加入队列。然后,在合适的时机(如事件处理函数结束),React会遍历这个队列,合并所有更新,计算出最终的状态,再一次性更新到DOM上。
在复杂列表渲染且频繁触发更新操作时手动控制批量更新
- 使用
unstable_batchedUpdates
:React提供了unstable_batchedUpdates
方法(在某些版本中),可以手动控制批量更新。 - 示例:
import React, { useState, unstable_batchedUpdates } from'react';
function List() {
const [list, setList] = useState([]);
const addItems = () => {
unstable_batchedUpdates(() => {
for (let i = 0; i < 10; i++) {
setList(prevList => [...prevList, i]);
}
});
};
return (
<div>
<button onClick={addItems}>Add Items</button>
<ul>
{list.map(item => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
在上述代码中,通过unstable_batchedUpdates
包裹多次setState
调用,使得这些更新操作在一个批次内处理,避免了多次不必要的DOM更新,从而达到最优性能。不过需要注意,unstable_batchedUpdates
可能会在后续版本中发生变化,使用时需关注官方文档。