CPPAlien / JS-QA

前端知识问答
0 stars 0 forks source link

react reconciliation #9

Open CPPAlien opened 5 years ago

CPPAlien commented 5 years ago

Two assumptions make O(n3) become O(n)

这两条假设看着简单,但理解起来确实让人摸不着头脑。这边的 different types 是指节点不同,比如 <Button> <Image> <Text> 这些。不同的节点,肯定意味着树不同。

React 采用广度优先的算法,来进行 virtual dom 树的比较。如果一颗树的子节点的 type 都不同,那么比较起来就比较简单,不同的节点就当作不同树进行替换就好。 image

但如果子节点的 type 有一样的,那要如何区分树相同还是不同呢? image

或者当你新增或删除一个相同的子节点时,你知道新增或删除了哪个? image

所以此时就需要第二条假设,除了用子节点类型来区分,还可以用一个 key 来区分。所以这边的 key 的主要作用是为了区分不同节点的,只是在用的好的话会带来性能上的优化

默认会使用 index 作为 key,一般情况下,只要不在子节点的前面和中间位置进行增删操作就没有问题。

有了key属性后,就可以与组件建立了一种对应关系,react根据key来决定是销毁重新创建组件还是更新组件。

key 需要稳定、可预测、并且唯一,不要使用 index 和 随机数作为key,使用随机数作为 key,会导致很多不必要的重建,影响性能。

{this.state.data.map((v,idx)=><Item key={idx} v={v} />)}
// 开始时:['a','b','c']=>
<ul>
    <li key="0">a <input type="text"/></li>
    <li key="1">b <input type="text"/></li>
    <li key="2">c <input type="text"/></li>
</ul>

// 数组重排 -> ['c','b','a'] =>
<ul>
    <li key="0">c <input type="text"/></li>
    <li key="1">b <input type="text"/></li>
    <li key="2">a <input type="text"/></li>
</ul>

上面实例中在数组重新排序后,key对应的实例都没有销毁,而是重新更新。具体更新过程我们拿key=0的元素来说明, 数组重新排序后:

CPPAlien commented 5 years ago

在 React 16 之前,如果一个列表中的 key 值相同,则后一个相同 key 值的元素不会被渲染出来。在 React 16 上,key 值相同可以被渲染,但会报一个 warning。