3. What are the functions and working mechanisms of key in VUE?

Create a demo

<button @click="set">set</button>
<p v-for="child in children">{{child}}</p><! Do not use key -->
<p v-for="child in children" :key="child">{{child}}</p><! -- use key -->-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- children js data statement: [' a ', 'b', 'c', 'd', 'e'] set () {this. Children. Splice (3, 0, 'f')} / set/get array after [' a ', 'b', 'c', 'f', 'd', 'e']Copy the code

Insert a key (f) in front of the fourth item (d) in the children array

Source location

url src\core\vdom\patch.js => updateChildren => sameVnode

while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
  if (isUndef(oldStartVnode)) {
    oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
  } else if (isUndef(oldEndVnode)) {
    oldEndVnode = oldCh[--oldEndIdx]
  } else if (sameVnode(oldStartVnode, newStartVnode)) {
    // Initial item comparison of old and new arrays
    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
    oldStartVnode = oldCh[++oldStartIdx]
    newStartVnode = newCh[++newStartIdx]
  } else if (sameVnode(oldEndVnode, newEndVnode)) {
    // Compare the last item of the old and new arrays
    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
    oldEndVnode = oldCh[--oldEndIdx]
    newEndVnode = newCh[--newEndIdx]
  } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
    oldStartVnode = oldCh[++oldStartIdx]
    newEndVnode = newCh[--newEndIdx]
  } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
    oldEndVnode = oldCh[--oldEndIdx]
    newStartVnode = newCh[++newStartIdx]
  } else {
    if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
    idxInOld = isDef(newStartVnode.key)
      ? oldKeyToIdx[newStartVnode.key]
      : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
    if (isUndef(idxInOld)) { // New element
      createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
    } else {
      vnodeToMove = oldCh[idxInOld]
      if (sameVnode(vnodeToMove, newStartVnode)) {
        patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
        oldCh[idxInOld] = undefined
        canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
      } else {
        // same key but different element. treat as new element
        createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
      }
    }
    newStartVnode = newCh[++newStartIdx]
  }
}
Copy the code

Execute without key code as follows

// Loop patch for the first time (because a.key = A.key does not render)
oldList:  a b c d e
newList:  a b c f d e

// Cycle patch 2 (same as 1)
oldList:  b c d e
newList:  b c f d e

// Cycle patch 3 (same as 1)
oldList:  c d e
newList:  c f d e

// Loop patch for the 4th time (although d.key = F.key, the content is changed and re-rendered)
oldList:  d e
newList:  f d e

// Cycle patch 5 (same as 4)
oldList:  e
newList:  d e

// run the following command to create a dom:
oldList:  
newList:  e
Copy the code

Conclusion: This shows that when the key is not set, the execution will be top-down, and the re-rendering operation will be performed when different locations are encountered. In the same way, the dom is re-rendered and then destroyed, which is a huge waste of performance.

Execute as follows using the key code

// Loop patch for the first time (because a.key = A.key does not render)
oldList:  a b c d e
newList:  a b c f d e

// Cycle patch 2 (same as 1)
oldList:  b c d e
newList:  b c f d e

// Cycle patch 3 (same as 1)
oldList:  c d e
newList:  c f d e

// loop the patch for the 4th time (now d.key! == F.key will compare from the last item)
oldList:  d e
newList:  f d e

// Cycle patch 5 (same as 4)
oldList:  d
newList:  f d

// select patch (old, f, new, f, d)
oldList:  
newList:  f
Copy the code

Conclusion: After setting the key, it will compare the first item first. If different items are encountered, it will compare the last item to avoid frequent updating of different elements and reduce DOM operations. nice

conclusion

  1. Key is mainly used to update virtual DOM efficiently. The principle is that during patch, VUE can accurately judge whether two nodes are the same by key, so as to avoid frequent updates of different elements, make the whole patch process more efficient, reduce DOM operation and improve performance.
  2. If the key is not set, different bugs may occur. For example, when switching between elements with the same label name, the key is used by the VUE to distinguish between them. If the key is not set, the VUE will only replace its internal attributes and not trigger the transition effect