Vue3 diff 算法不传递 key的影响

86 阅读1分钟

不传递key,就是单纯在 for 循环中根据索引来确定元素,只要当前索引下,新旧子节点的类型不一样,就不会复用该旧元素元素,而且先卸载 旧节点,再挂载新节点,造成性能浪费

const oldNode = [
    {
        type: 'p',
    },
    {
        type: 'span',
    },
]
const newNode = [
    {
        type: 'span',
    }
    {
        type: 'p'
    }
]

/**
 * 一共需要4次操作才能完成Dom的更新
 *  1. newVnode[0] oldNode[0] 直接patch(oldNode[0],newNode[0]),由于类型不一样,patch函数先把旧的 p节点删除,然后再次挂载 span节点
 *  2. 同上操作
 */
 

代码解析

function patchChildren(n1,n2,container) {
    if (typeof n2.children === 'string') {
        // ...
    } else if (Array.isArray(n2.children)) {
        if (Array.isArray(n1.children)) {
            for (let i = 0; i < n2.children.length; i ++) {
                const newNode = n2.children[i]
                const oldNode = n1.children[i]
                /**
                1. 旧节点中拿到了 type: p 类型的节点,新节点中拿到了 type: span的节点,直接调用 patch函数,patch函数处理时 n1.type(旧节点) !== n2.type(新节点) ,直接卸载了旧节点
                2. 同上处理 type: span 和 type:p 类型的节点
                 * oldNode.type !== newNode.type 类型不一样,oldNode直接被卸载,然后挂载 newNode
                 */
                patch(oldNode,newNode,container)
            }
        }
    }
}
function patch(n1,n2,container) {
    if (!n1) {
        mountElement(n2,container)
    } else {
        if(n1.type !== n2.type) {
            // 都是走到了这里,直接把 旧节点卸载了
            unmount(n1)
            n1 = null
        }
        const {type} = n2
        if (typeof n2 === 'string'){
            if (!n1){
                // 挂载 n2
                mountElement(n2)
            }
        }
        
    }
}