Skip to content

Commit c7620b2

Browse files
committed
fix(patch): warn error when vnode with duplicate key
1 parent bd4819e commit c7620b2

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

src/core/vdom/patch.js

+24-7
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ export function createPatchFunction (backend) {
263263

264264
function createChildren (vnode, children, insertedVnodeQueue) {
265265
if (Array.isArray(children)) {
266+
if (process.env.NODE_ENV !== 'production') {
267+
checkChildren(children)
268+
}
266269
for (let i = 0; i < children.length; ++i) {
267270
createElm(children[i], insertedVnodeQueue, vnode.elm, null, true)
268271
}
@@ -394,6 +397,10 @@ export function createPatchFunction (backend) {
394397
// during leaving transitions
395398
const canMove = !removeOnly
396399

400+
if (process.env.NODE_ENV !== 'production') {
401+
checkChildren(newCh)
402+
}
403+
397404
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
398405
if (isUndef(oldStartVnode)) {
399406
oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
@@ -426,13 +433,6 @@ export function createPatchFunction (backend) {
426433
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
427434
} else {
428435
vnodeToMove = oldCh[idxInOld]
429-
/* istanbul ignore if */
430-
if (process.env.NODE_ENV !== 'production' && !vnodeToMove) {
431-
warn(
432-
'It seems there are duplicate keys that is causing an update error. ' +
433-
'Make sure each v-for item has a unique key.'
434-
)
435-
}
436436
if (sameVnode(vnodeToMove, newStartVnode)) {
437437
patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue)
438438
oldCh[idxInOld] = undefined
@@ -453,6 +453,23 @@ export function createPatchFunction (backend) {
453453
}
454454
}
455455

456+
function checkChildren (children) {
457+
const cache = {}
458+
459+
for (let i = 0; i < children.length; i++) {
460+
const vnode = children[i]
461+
const key = vnode.key
462+
463+
if (key != null) {
464+
if (cache[key]) {
465+
warn(`The duplicate keys: '${key}' that is causing an update error.`)
466+
} else {
467+
cache[key] = true
468+
}
469+
}
470+
}
471+
}
472+
456473
function findIdxInOld (node, oldCh, start, end) {
457474
for (let i = start; i < end; i++) {
458475
const c = oldCh[i]

test/unit/features/component/component.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ describe('Component', () => {
166166
const vm = new Vue({
167167
template:
168168
'<div>' +
169-
'<component v-for="c in comps" :key="c.type" :is="c.type"></component>' +
169+
'<component v-for="(c, i) in comps" :key="i" :is="c.type"></component>' +
170170
'</div>',
171171
data: {
172172
comps: [{ type: 'one' }, { type: 'two' }]

test/unit/modules/vdom/patch/children.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -507,4 +507,27 @@ describe('vdom patch: children', () => {
507507

508508
expect(postPatch).toBe(original)
509509
})
510+
511+
it('should warn with duplicate keys: createChildren', () => {
512+
function makeNode (key) {
513+
return new VNode('div', { key: key })
514+
}
515+
516+
const vnode = new VNode('p', {}, ['b', 'a', 'c', 'b'].map(makeNode))
517+
patch(null, vnode)
518+
expect('The duplicate keys: \'b\' that is causing an update error.').toHaveBeenWarned()
519+
})
520+
521+
it('should warn with duplicate keys: updateChildren', () => {
522+
function makeNode (key) {
523+
return new VNode('div', { key: key })
524+
}
525+
526+
const vnode2 = new VNode('p', {}, ['b', 'a', 'c', 'b'].map(makeNode))
527+
const vnode3 = new VNode('p', {}, ['b', 'x', 'd', 'b'].map(makeNode))
528+
patch(vnode0, vnode2)
529+
expect('The duplicate keys: \'b\' that is causing an update error.').toHaveBeenWarned()
530+
patch(vnode2, vnode3)
531+
expect('The duplicate keys: \'b\' that is causing an update error.').toHaveBeenWarned()
532+
})
510533
})

0 commit comments

Comments
 (0)