Skip to content

Commit

Permalink
fix: dynamically update deep scopedSlot refs (#899)
Browse files Browse the repository at this point in the history
  • Loading branch information
chearon committed Feb 7, 2022
1 parent 4a4ed5d commit ef312a3
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
9 changes: 3 additions & 6 deletions src/mixin.ts
Expand Up @@ -14,7 +14,7 @@ import {
import { ref } from './apis'
import vmStateManager from './utils/vmStateManager'
import {
updateTemplateRef,
afterRender,
activateCurrentInstance,
resolveScopedSlots,
asVmProperty,
Expand All @@ -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)
},
})

Expand Down
16 changes: 15 additions & 1 deletion src/utils/instance.ts
@@ -1,3 +1,4 @@
import type { VNode } from 'vue'
import { ComponentInstance } from '../component'
import vmStateManager from './vmStateManager'
import {
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down
30 changes: 30 additions & 0 deletions test/templateRefs.spec.js
Expand Up @@ -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: `<div><foo #default>Slot: <div ref="divRef" v-if="showDiv" /></foo></div>`,
components: {
foo: {
components: {
bar: {
template: `<div><slot /></div>`,
},
},
template: '<div><bar #default><slot /></bar></div>',
},
},
}).$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;
Expand Down

0 comments on commit ef312a3

Please sign in to comment.