我正在检查react reconciliation。它说,遍历孩子时,React会同时遍历两个孩子列表,并在有差异时生成一个突变。
我举了一个简单的例子:
class ComponentA extends React.Component {
state = {
first: true
}
clickHandler = () => {
this.setState({
first: !this.state.first
})
}
render() {
return (
<div className='top'>
{this.state.first ? <span>xyz</span> : undefined}
<div>abc</div>
<div>efg</div>
<button onClick={this.clickHandler}>click me</button>
</div>)
}
}
单击时,第一个孩子(span元素)将进入和退出孩子列表。从React的角度来看,一个接一个地迭代,看起来所有元素都已更改。因此,React应该为所有这四个子项(包括按钮)重新渲染DOM。
但是在Firefox和Chrome中检查DOM检查器时,我发现仅在 span 元素上高亮显示,而不是在所有四个元素上高亮显示,这意味着DOM保留了三个不变的元素。为什么?
答案 0 :(得分:0)
在这种情况下,React比较元素属性。来自React文档:
相同类型的DOM元素
当比较两个React DOM元素时 相同的类型,React查看两者的属性,保持相同 底层DOM节点,并且仅更新更改的属性。对于 例如:
这也是在动态创建元素列表时需要提供密钥的原因。如果未提供该键,并且列表由于属性或状态更改而更改,则需要删除并附加所有列表项。
您可能想阅读下面的文章,其中对这种现象进行了更彻底的解释。 https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
摘自文章:
让我解释一下,密钥是React用来识别DOM的唯一东西 元素。如果将项目推送到列表或将其删除会发生什么 中间有东西吗?如果密钥与React之前假设的相同 DOM元素代表与以前相同的组件。但是那 不再是真的。
答案 1 :(得分:0)
在我的示例中发生的事情是,第一个孩子(JSON_THROW_ON_ERROR
)从未真正从children数组中删除,而是仅在span
和undefined之间切换。因此,总是有4个孩子,并且重新排序(索引移位)永远不会发生。
这就是为什么react知道匹配元素并仅更新跨度span
元素,而其余三个保持不变的原因。