Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e09b67a

Browse files
committed
fix(runtime-vapor): clear template ref when switching to unresolved async component
1 parent a2e32e0 commit e09b67a

2 files changed

Lines changed: 85 additions & 4 deletions

File tree

‎packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,4 +2278,77 @@ describe('VaporKeepAlive', () => {
22782278
expect(mountedSpy).toHaveBeenCalledTimes(0)
22792279
expect(activatedSpy).toHaveBeenCalledTimes(0)
22802280
})
2281+
2282+
test('should clear template ref when switching to unresolved async component', async () => {
2283+
const timeout = (n: number = 0) => new Promise(r => setTimeout(r, n))
2284+
2285+
let resolveAsync: (comp: any) => void
2286+
const AsyncComp = defineVaporAsyncComponent(
2287+
() =>
2288+
new Promise(r => {
2289+
resolveAsync = r
2290+
}),
2291+
)
2292+
2293+
const Comp = defineVaporComponent({
2294+
name: 'Comp',
2295+
setup() {
2296+
return template('<div>comp</div>')()
2297+
},
2298+
})
2299+
2300+
const instanceRef = ref<any>(null)
2301+
const toggle = ref(false)
2302+
2303+
define({
2304+
setup() {
2305+
const setRef = createTemplateRefSetter()
2306+
return createComponent(VaporKeepAlive, null, {
2307+
default: () =>
2308+
createIf(
2309+
() => toggle.value,
2310+
() => {
2311+
const comp = createComponent(AsyncComp)
2312+
setRef(comp, instanceRef)
2313+
return comp
2314+
},
2315+
() => {
2316+
const comp = createComponent(Comp)
2317+
setRef(comp, instanceRef)
2318+
return comp
2319+
},
2320+
),
2321+
})
2322+
},
2323+
}).render()
2324+
2325+
await nextTick()
2326+
// Comp is mounted — ref should point to it
2327+
expect(instanceRef.value).not.toBe(null)
2328+
2329+
// switch to async component (unresolved)
2330+
toggle.value = true
2331+
await nextTick()
2332+
// ref should be null while async is pending
2333+
expect(instanceRef.value).toBe(null)
2334+
2335+
// resolve async
2336+
resolveAsync!(
2337+
defineVaporComponent({
2338+
name: 'AsyncResolved',
2339+
setup() {
2340+
return template('<div>async</div>')()
2341+
},
2342+
}),
2343+
)
2344+
await timeout()
2345+
await nextTick()
2346+
// ref should now point to the resolved component
2347+
expect(instanceRef.value).not.toBe(null)
2348+
2349+
// switch back to Comp
2350+
toggle.value = false
2351+
await nextTick()
2352+
expect(instanceRef.value).not.toBe(null)
2353+
})
22812354
})

‎packages/runtime-vapor/src/apiTemplateRef.ts‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,12 @@ function setRef(
108108

109109
// async component
110110
if (isVaporComponent(el) && isAsyncWrapper(el)) {
111-
// unresolved: handled in DynamicFragment's updated hook
112-
if (!el.type.__asyncResolved) return
113-
114111
// resolved: set ref to the inner component
115-
el = (el.block as DynamicFragment).nodes as VaporComponentInstance
112+
if (el.type.__asyncResolved) {
113+
el = (el.block as DynamicFragment).nodes as VaporComponentInstance
114+
}
115+
// unresolved: el stays as async wrapper, getRefValue returns null
116+
// → ref will be cleared through normal setRef logic below
116117
}
117118

118119
const setupState: any = __DEV__ ? instance.setupState || {} : null
@@ -198,6 +199,11 @@ function setRef(
198199
if (_isString || _isRef) {
199200
const doSet: SchedulerJob = () => {
200201
if (refFor) {
202+
// for unresolved async components, refValue is null.
203+
// skip adding null to the array — the ref will be re-set
204+
// when the async component resolves via DynamicFragment's updated hook.
205+
if (refValue == null) return
206+
201207
existing = _isString
202208
? __DEV__ && canSetSetupRef(ref)
203209
? setupState[ref]
@@ -262,6 +268,8 @@ function setRef(
262268

263269
const getRefValue = (el: RefEl) => {
264270
if (isVaporComponent(el)) {
271+
// unresolved async wrapper: return null so ref gets cleared
272+
if (isAsyncWrapper(el) && !el.type.__asyncResolved) return null
265273
return getExposed(el) || el
266274
} else if (isTeleportFragment(el)) {
267275
return null

0 commit comments

Comments
 (0)