Skip to content

Commit

Permalink
fix(runtime-core): separate null vs. non-null ref value updates (#1835)
Browse files Browse the repository at this point in the history
fix #1789, fix #1834
  • Loading branch information
HcySunYang authored Aug 13, 2020
1 parent b14f4a5 commit 3991ff0
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 5 deletions.
57 changes: 57 additions & 0 deletions packages/runtime-core/__tests__/apiTemplateRef.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,61 @@ describe('api: template refs', () => {
// ref should be updated
expect(serializeInner(root)).toBe(`<div id="foo">foo</div>`)
})

// #1834
test('exchange refs', async () => {
const refToggle = ref(false)
const spy = jest.fn()

const Comp = {
render(this: any) {
return [
h('p', { ref: refToggle.value ? 'foo' : 'bar' }),
h('i', { ref: refToggle.value ? 'bar' : 'foo' })
]
},
mounted(this: any) {
spy(this.$refs.foo.tag, this.$refs.bar.tag)
},
updated(this: any) {
spy(this.$refs.foo.tag, this.$refs.bar.tag)
}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)

expect(spy.mock.calls[0][0]).toBe('i')
expect(spy.mock.calls[0][1]).toBe('p')
refToggle.value = true
await nextTick()
expect(spy.mock.calls[1][0]).toBe('p')
expect(spy.mock.calls[1][1]).toBe('i')
})

// #1789
test('toggle the same ref to different elements', async () => {
const refToggle = ref(false)
const spy = jest.fn()

const Comp = {
render(this: any) {
return refToggle.value ? h('p', { ref: 'foo' }) : h('i', { ref: 'foo' })
},
mounted(this: any) {
spy(this.$refs.foo.tag)
},
updated(this: any) {
spy(this.$refs.foo.tag)
}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)

expect(spy.mock.calls[0][0]).toBe('i')
refToggle.value = true
await nextTick()
expect(spy.mock.calls[1][0]).toBe('p')
})
})
24 changes: 19 additions & 5 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,28 @@ export const setRef = (
}

if (isString(ref)) {
refs[ref] = value
if (hasOwn(setupState, ref)) {
queuePostRenderEffect(() => {
const doSet = () => {
refs[ref] = value
if (hasOwn(setupState, ref)) {
setupState[ref] = value
}, parentSuspense)
}
}
// #1789: for non-null values, set them after render
// null values means this is unmount and it should not overwrite another
// ref with the same key
if (value) {
queuePostRenderEffect(doSet, parentSuspense)
} else {
doSet()
}
} else if (isRef(ref)) {
ref.value = value
if (value) {
queuePostRenderEffect(() => {
ref.value = value
}, parentSuspense)
} else {
ref.value = value
}
} else if (isFunction(ref)) {
callWithErrorHandling(ref, parentComponent, ErrorCodes.FUNCTION_REF, [
value,
Expand Down

0 comments on commit 3991ff0

Please sign in to comment.