Skip to content

Commit 90336e9

Browse files
committed
feat: support async setup (fix #463)
1 parent 3d9e1f2 commit 90336e9

File tree

4 files changed

+74
-6
lines changed

4 files changed

+74
-6
lines changed

src/helpers.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ComponentOptions, ShallowUnwrapRef, Ref } from 'vue'
22

3-
import { Vue, VueConstructor, VueMixin } from './vue'
3+
import { Vue, VueBase, VueConstructor, VueMixin } from './vue'
44

55
export function Options<V extends Vue>(
66
options: ComponentOptions & ThisType<V>
@@ -80,10 +80,12 @@ export type UnwrapSetupValue<T> = T extends Ref<infer R>
8080
? R
8181
: ShallowUnwrapRef<T>
8282

83-
export function setup<R>(setupFn: () => R): UnwrapSetupValue<R> {
83+
export type UnwrapPromise<T> = T extends Promise<infer R> ? R : T
84+
85+
export function setup<R>(setupFn: () => R): UnwrapSetupValue<UnwrapPromise<R>> {
8486
// Hack to delay the invocation of setup function.
8587
// Will be called after dealing with class properties.
8688
return {
8789
__s: setupFn,
88-
} as UnwrapSetupValue<R>
90+
} as UnwrapSetupValue<UnwrapPromise<R>>
8991
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ export {
3838
UnionToIntersection,
3939
ExtractInstance,
4040
UnwrapSetupValue,
41+
UnwrapPromise,
4142
} from './helpers'

src/vue.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ class VueImpl {
243243
const dataKeys = Object.keys(data)
244244

245245
const plainData: any = {}
246+
let promise: Promise<any> | null = null
246247

247248
// Initialize reactive data and convert constructor `this` to a proxy
248249
dataKeys.forEach((key) => {
@@ -260,11 +261,23 @@ class VueImpl {
260261
dataKeys.forEach((key) => {
261262
if (data[key] && data[key].__s) {
262263
const setupState = data[key].__s()
263-
plainData[key] = proxyRefs(setupState)
264+
if (setupState instanceof Promise) {
265+
if (!promise) {
266+
promise = Promise.resolve(plainData)
267+
}
268+
promise = promise.then(() => {
269+
return setupState.then((value) => {
270+
plainData[key] = proxyRefs(value)
271+
return plainData
272+
})
273+
})
274+
} else {
275+
plainData[key] = proxyRefs(setupState)
276+
}
264277
}
265278
})
266279

267-
return plainData
280+
return promise ?? plainData
268281
}
269282

270283
const decorators =

test/specs/test.spec.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
import 'reflect-metadata'
2-
import { h, resolveComponent, ref, onMounted, Ref, watch, toRef } from 'vue'
2+
import {
3+
h,
4+
resolveComponent,
5+
ref,
6+
onMounted,
7+
Ref,
8+
watch,
9+
toRef,
10+
nextTick,
11+
Suspense,
12+
} from 'vue'
313
import { Options, createDecorator, mixins, Vue, setup, prop } from '../../src'
414
import { mount, unmount } from '../helpers'
515

@@ -416,6 +426,48 @@ describe('vue-class-component', () => {
416426
expect(root.answer.nested.answer.value).toBe(42)
417427
})
418428

429+
it('setup: suspense', () => {
430+
const deps: Promise<any>[] = []
431+
432+
class Child extends Vue {
433+
foo = 'Hello'
434+
435+
bar = setup(() => {
436+
const a = ref(42)
437+
return {
438+
a,
439+
}
440+
})
441+
442+
baz = setup(() => {
443+
const b = ref(true)
444+
const p = Promise.resolve({
445+
b,
446+
})
447+
deps.push(p.then(() => Promise.resolve()))
448+
return p
449+
})
450+
451+
render() {
452+
return h('div', [[this.foo, this.bar.a, this.baz.b].join(',')])
453+
}
454+
}
455+
456+
class App extends Vue {
457+
render() {
458+
return h(Suspense, null, {
459+
default: h(Child),
460+
fallback: h('div', 'fallback'),
461+
})
462+
}
463+
}
464+
465+
const { root } = mount(App)
466+
return Promise.all(deps)
467+
.then(() => nextTick())
468+
.then(() => expect(root.$el.textContent).toBe('Hello,42,true'))
469+
})
470+
419471
it('reactive class properties in a composition function', (done) => {
420472
function test(message: Ref<string>) {
421473
watch(message, () => {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy