为什么当订单改变时,React Reconciliation 会保留不变的兄弟姐妹

Why does react reconciliation preserve the constant sibilings when order is changed

我正在查看 react reconciliation。它说当遍历 children 时,React 将同时遍历 children 的两个列表,并在有差异时生成突变。

我做了一个简单的例子:

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>)
    }
}

单击时,第一个 child(span 元素)将进出 children 的列表。从 React 的角度来看,一个一个地迭代,应该看起来所有的元素都发生了变化。因此 React 应该 re-render 所有这 4 children(包括按钮)的 DOM。

但是在 Firefox 和 Chrome 中检查 DOM 检查器时,我只在 span 元素上看到高亮显示,而不是在所有四个元素上,这意味着 DOM 为三个未更改的元素保留。为什么?

(这张图片上没有突出显示,但 span 元素在单击按钮时突出显示)

React 在这种情况下比较元素属性。来自 React 文档:

DOM Elements Of The Same Type

When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes. For example:

这也是您在动态创建元素列表时需要提供键的原因。如果未提供该键并且列表因道具或状态更改而更改,则需要删除和附加所有列表项。

您可能需要阅读以下文章,其中对这种现象有更详尽的解释。 https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

来自文章:

Let me explain, a key is the only thing React uses to identify DOM elements. What happens if you push an item to the list or remove something in the middle? If the key is same as before React assumes that the DOM element represents the same component as before. But that is no longer true.

在我的示例中发生的情况是,第一个 child(span)从未真正从 children 数组中删除,而只是在 spanspan 之间切换不明确的。所以总是有 4 children 并且重新排序(索引移位)永远不会发生。

这就是为什么 React 知道匹配元素并只更新 span DOM 元素并保留其他 3 个元素。