Skip to content

Commit

Permalink
fix(runtime-core): cloneVNode should preserve correct ctx instance wh…
Browse files Browse the repository at this point in the history
…en normalizing ref

fix #1311
  • Loading branch information
yyx990803 committed Jun 15, 2020
1 parent 605953a commit be69bee
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 15 deletions.
56 changes: 44 additions & 12 deletions packages/runtime-core/__tests__/vnode.spec.ts
Expand Up @@ -14,6 +14,7 @@ import { Data } from '../src/component'
import { ShapeFlags, PatchFlags } from '@vue/shared'
import { h, reactive, isReactive } from '../src'
import { createApp, nodeOps, serializeInner } from '@vue/runtime-test'
import { setCurrentRenderingInstance } from '../src/componentRenderUtils'

describe('vnode', () => {
test('create with just tag', () => {
Expand Down Expand Up @@ -198,24 +199,55 @@ describe('vnode', () => {
expect(cloned2).toEqual(node2)
expect(cloneVNode(node2)).toEqual(node2)
expect(cloneVNode(node2)).toEqual(cloned2)
})

test('cloneVNode key normalization', () => {
// #1041 should use resolved key/ref
expect(cloneVNode(createVNode('div', { key: 1 })).key).toBe(1)
expect(cloneVNode(createVNode('div', { key: 1 }), { key: 2 }).key).toBe(2)
expect(cloneVNode(createVNode('div'), { key: 2 }).key).toBe(2)
})

// ref normalizes to [currentRenderingInstance, ref]
test('cloneVNode ref normalization', () => {
const mockInstance1 = {} as any
const mockInstance2 = {} as any

setCurrentRenderingInstance(mockInstance1)
const original = createVNode('div', { ref: 'foo' })
expect(original.ref).toEqual([mockInstance1, 'foo'])

// clone and preserve original ref
const cloned1 = cloneVNode(original)
expect(cloned1.ref).toEqual([mockInstance1, 'foo'])

// cloning with new ref, but with same context instance
const cloned2 = cloneVNode(original, { ref: 'bar' })
expect(cloned2.ref).toEqual([mockInstance1, 'bar'])

// cloning and adding ref to original that has no ref
const original2 = createVNode('div')
const cloned3 = cloneVNode(original2, { ref: 'bar' })
expect(cloned3.ref).toEqual([mockInstance1, 'bar'])

// cloning with different context instance
setCurrentRenderingInstance(mockInstance2)

// clone and preserve original ref
const cloned4 = cloneVNode(original)
// #1311 should preserve original context instance!
expect(cloned4.ref).toEqual([mockInstance1, 'foo'])

// cloning with new ref, but with same context instance
const cloned5 = cloneVNode(original, { ref: 'bar' })
// new ref should use current context instance and overwrite orgiinal
expect(cloned5.ref).toEqual([mockInstance2, 'bar'])

// cloning and adding ref to original that has no ref
const cloned6 = cloneVNode(original2, { ref: 'bar' })
expect(cloned6.ref).toEqual([mockInstance2, 'bar'])

// ref normalizes to [currentRenderingInstance, ref]
expect(cloneVNode(createVNode('div', { ref: 'foo' })).ref).toEqual([
null,
'foo'
])
expect(
cloneVNode(createVNode('div', { ref: 'foo' }), { ref: 'bar' }).ref
).toEqual([null, 'bar'])
expect(cloneVNode(createVNode('div'), { ref: 'bar' }).ref).toEqual([
null,
'bar'
])
setCurrentRenderingInstance(null)
})

describe('mergeProps', () => {
Expand Down
7 changes: 4 additions & 3 deletions packages/runtime-core/src/vnode.ts
Expand Up @@ -277,12 +277,13 @@ export const InternalObjectKey = `__vInternal`
const normalizeKey = ({ key }: VNodeProps): VNode['key'] =>
key != null ? key : null

const normalizeRef = ({ ref }: VNodeProps): VNode['ref'] =>
(ref != null
const normalizeRef = ({ ref }: VNodeProps): VNode['ref'] => {
return (ref != null
? isArray(ref)
? ref
: [currentRenderingInstance!, ref]
: null) as any
}

export const createVNode = (__DEV__
? createVNodeWithArgsTransform
Expand Down Expand Up @@ -420,7 +421,7 @@ export function cloneVNode<T, U>(
type: vnode.type,
props,
key: props && normalizeKey(props),
ref: props && normalizeRef(props),
ref: extraProps && extraProps.ref ? normalizeRef(extraProps) : vnode.ref,
scopeId: vnode.scopeId,
children: vnode.children,
target: vnode.target,
Expand Down

0 comments on commit be69bee

Please sign in to comment.