diff --git a/src/mixin.ts b/src/mixin.ts index fb714135..dc100fda 100644 --- a/src/mixin.ts +++ b/src/mixin.ts @@ -14,7 +14,7 @@ import { import { ref } from './apis' import vmStateManager from './utils/vmStateManager' import { - updateTemplateRef, + afterRender, activateCurrentInstance, resolveScopedSlots, asVmProperty, @@ -31,16 +31,13 @@ export function mixin(Vue: VueConstructor) { Vue.mixin({ beforeCreate: functionApiInit, mounted(this: ComponentInstance) { - updateTemplateRef(this) + afterRender(this) }, beforeUpdate() { updateVmAttrs(this as ComponentInstance) }, updated(this: ComponentInstance) { - updateTemplateRef(this) - if (this.$vnode?.context) { - updateTemplateRef(this.$vnode.context) - } + afterRender(this) }, }) diff --git a/src/utils/instance.ts b/src/utils/instance.ts index 5544f976..9a5be538 100644 --- a/src/utils/instance.ts +++ b/src/utils/instance.ts @@ -1,3 +1,4 @@ +import type { VNode } from 'vue' import { ComponentInstance } from '../component' import vmStateManager from './vmStateManager' import { @@ -76,7 +77,7 @@ export function asVmProperty( } } -export function updateTemplateRef(vm: ComponentInstance) { +function updateTemplateRef(vm: ComponentInstance) { const rawBindings = vmStateManager.get(vm, 'rawBindings') || {} if (!rawBindings || !Object.keys(rawBindings).length) return @@ -103,6 +104,19 @@ export function updateTemplateRef(vm: ComponentInstance) { vmStateManager.set(vm, 'refs', validNewKeys) } +export function afterRender(vm: ComponentInstance) { + const stack = [(vm as any)._vnode as VNode] + while (stack.length) { + const vnode = stack.pop()! + if (vnode.context) updateTemplateRef(vnode.context) + if (vnode.children) { + for (let i = 0; i < vnode.children.length; ++i) { + stack.push(vnode.children[i]) + } + } + } +} + export function updateVmAttrs(vm: ComponentInstance, ctx?: SetupContext) { if (!vm) { return diff --git a/test/templateRefs.spec.js b/test/templateRefs.spec.js index f41ec845..2becd297 100644 --- a/test/templateRefs.spec.js +++ b/test/templateRefs.spec.js @@ -113,6 +113,36 @@ describe('ref', () => { //@ts-ignore expect(vm.$refs.barRef).toBe(vm.barRef) }) + + it('should update deeply nested component refs using scoped slots', async () => { + const vm = new Vue({ + setup() { + const divRef = ref(null) + const showDiv = ref(false) + return { + divRef, + showDiv, + } + }, + template: `
Slot:
`, + components: { + foo: { + components: { + bar: { + template: `
`, + }, + }, + template: '
', + }, + }, + }).$mount() + await nextTick() + //@ts-ignore + vm.showDiv = true + await nextTick() + //@ts-ignore + expect(vm.$refs.divRef).toBe(vm.divRef) + }) // TODO: how ? // it('work with createElement', () => { // let root;