refactor: remove unnecessary functional wrapper + delay for async components
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { ChildrenFlags } from '../flags'
|
||||
import { createComponentVNode, VNodeData } from '../vdom'
|
||||
import { Component, ComponentType, FunctionalComponent } from '../component'
|
||||
import { createComponentVNode, Slots } from '../vdom'
|
||||
import { Component, ComponentType, ComponentClass } from '../component'
|
||||
|
||||
export interface AsyncComponentFactory {
|
||||
(): Promise<ComponentType>
|
||||
@@ -22,92 +22,90 @@ export type AsyncComponentOptions =
|
||||
interface AsyncContainerData {
|
||||
comp: ComponentType | null
|
||||
err: Error | null
|
||||
delayed: boolean
|
||||
timedOut: boolean
|
||||
}
|
||||
|
||||
interface AsyncContainerProps {
|
||||
options: AsyncComponentFullOptions
|
||||
rawData: VNodeData | null
|
||||
}
|
||||
|
||||
export class AsyncContainer extends Component<
|
||||
AsyncContainerData,
|
||||
AsyncContainerProps
|
||||
> {
|
||||
data() {
|
||||
return {
|
||||
comp: null,
|
||||
err: null,
|
||||
timedOut: false
|
||||
}
|
||||
}
|
||||
|
||||
created() {
|
||||
const { factory, timeout } = this.$props.options
|
||||
if (factory.resolved) {
|
||||
this.comp = factory.resolved
|
||||
} else {
|
||||
factory()
|
||||
.then(resolved => {
|
||||
this.comp = factory.resolved = resolved
|
||||
})
|
||||
.catch(err => {
|
||||
this.err = err
|
||||
})
|
||||
}
|
||||
if (timeout != null) {
|
||||
setTimeout(() => {
|
||||
this.timedOut = true
|
||||
}, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
render(props: AsyncContainerProps) {
|
||||
if (this.err || (this.timedOut && !this.comp)) {
|
||||
const error =
|
||||
this.err ||
|
||||
new Error(`Async component timed out after ${props.options.timeout}ms.`)
|
||||
const errorComp = props.options.error
|
||||
return errorComp
|
||||
? createComponentVNode(
|
||||
errorComp,
|
||||
{ error },
|
||||
null,
|
||||
ChildrenFlags.NO_CHILDREN
|
||||
)
|
||||
: null
|
||||
} else if (this.comp) {
|
||||
return createComponentVNode(
|
||||
this.comp,
|
||||
props.rawData,
|
||||
null,
|
||||
ChildrenFlags.UNKNOWN_CHILDREN
|
||||
)
|
||||
} else {
|
||||
const loadingComp = props.options.loading
|
||||
return loadingComp
|
||||
? createComponentVNode(
|
||||
loadingComp,
|
||||
null,
|
||||
null,
|
||||
ChildrenFlags.NO_CHILDREN
|
||||
)
|
||||
: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createAsyncComponent(
|
||||
options: AsyncComponentOptions
|
||||
): FunctionalComponent {
|
||||
): ComponentClass {
|
||||
if (typeof options === 'function') {
|
||||
options = { factory: options }
|
||||
}
|
||||
return (_, __, ___, rawData) =>
|
||||
createComponentVNode(
|
||||
AsyncContainer,
|
||||
{ options, rawData },
|
||||
null,
|
||||
ChildrenFlags.NO_CHILDREN
|
||||
)
|
||||
|
||||
const {
|
||||
factory,
|
||||
timeout,
|
||||
delay = 200,
|
||||
loading: loadingComp,
|
||||
error: errorComp
|
||||
} = options
|
||||
|
||||
return class AsyncContainer extends Component<AsyncContainerData> {
|
||||
data() {
|
||||
return {
|
||||
comp: null,
|
||||
err: null,
|
||||
delayed: false,
|
||||
timedOut: false
|
||||
}
|
||||
}
|
||||
|
||||
// doing this in beforeMount so this is non-SSR only
|
||||
beforeMount() {
|
||||
if (factory.resolved) {
|
||||
this.comp = factory.resolved
|
||||
} else {
|
||||
factory()
|
||||
.then(resolved => {
|
||||
this.comp = factory.resolved = resolved
|
||||
})
|
||||
.catch(err => {
|
||||
this.err = err
|
||||
})
|
||||
}
|
||||
if (timeout != null) {
|
||||
setTimeout(() => {
|
||||
this.timedOut = true
|
||||
}, timeout)
|
||||
}
|
||||
if (delay != null) {
|
||||
this.delayed = true
|
||||
setTimeout(() => {
|
||||
this.delayed = false
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
render(props: any, slots: Slots) {
|
||||
if (this.err || (this.timedOut && !this.comp)) {
|
||||
const error =
|
||||
this.err || new Error(`Async component timed out after ${timeout}ms.`)
|
||||
return errorComp
|
||||
? createComponentVNode(
|
||||
errorComp,
|
||||
{ error },
|
||||
null,
|
||||
ChildrenFlags.NO_CHILDREN
|
||||
)
|
||||
: null
|
||||
} else if (this.comp) {
|
||||
return createComponentVNode(
|
||||
this.comp,
|
||||
props,
|
||||
slots,
|
||||
ChildrenFlags.STABLE_SLOTS
|
||||
)
|
||||
} else {
|
||||
return loadingComp && !this.delayed
|
||||
? createComponentVNode(
|
||||
loadingComp,
|
||||
null,
|
||||
null,
|
||||
ChildrenFlags.NO_CHILDREN
|
||||
)
|
||||
: null
|
||||
}
|
||||
}
|
||||
} as ComponentClass
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user