fix(runtime-core): dynamic component should support falsy values without warning
This commit is contained in:
parent
f3a9b516bd
commit
ded92f93b4
@ -8,7 +8,9 @@ import {
|
|||||||
resolveDynamicComponent,
|
resolveDynamicComponent,
|
||||||
h,
|
h,
|
||||||
serializeInner,
|
serializeInner,
|
||||||
createVNode
|
createVNode,
|
||||||
|
Comment,
|
||||||
|
VNode
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { mockWarn } from '@vue/shared'
|
import { mockWarn } from '@vue/shared'
|
||||||
|
|
||||||
@ -102,6 +104,7 @@ describe('resolveAssets', () => {
|
|||||||
baz: { render: () => 'baz' }
|
baz: { render: () => 'baz' }
|
||||||
}
|
}
|
||||||
let foo, bar, baz // dynamic components
|
let foo, bar, baz // dynamic components
|
||||||
|
let dynamicVNode: VNode
|
||||||
|
|
||||||
const Child = {
|
const Child = {
|
||||||
render(this: any) {
|
render(this: any) {
|
||||||
@ -115,6 +118,7 @@ describe('resolveAssets', () => {
|
|||||||
return () => {
|
return () => {
|
||||||
foo = resolveDynamicComponent('foo') // <component is="foo"/>
|
foo = resolveDynamicComponent('foo') // <component is="foo"/>
|
||||||
bar = resolveDynamicComponent(dynamicComponents.bar) // <component :is="bar"/>, function
|
bar = resolveDynamicComponent(dynamicComponents.bar) // <component :is="bar"/>, function
|
||||||
|
dynamicVNode = createVNode(resolveDynamicComponent(null)) // <component :is="null"/>
|
||||||
return h(Child, () => {
|
return h(Child, () => {
|
||||||
// check inside child slots
|
// check inside child slots
|
||||||
baz = resolveDynamicComponent(dynamicComponents.baz) // <component :is="baz"/>, object
|
baz = resolveDynamicComponent(dynamicComponents.baz) // <component :is="baz"/>, object
|
||||||
@ -129,6 +133,8 @@ describe('resolveAssets', () => {
|
|||||||
expect(foo).toBe(dynamicComponents.foo)
|
expect(foo).toBe(dynamicComponents.foo)
|
||||||
expect(bar).toBe(dynamicComponents.bar)
|
expect(bar).toBe(dynamicComponents.bar)
|
||||||
expect(baz).toBe(dynamicComponents.baz)
|
expect(baz).toBe(dynamicComponents.baz)
|
||||||
|
// should allow explicit falsy type to remove the component
|
||||||
|
expect(dynamicVNode!.type).toBe(Comment)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('resolve dynamic component should fallback to plain element without warning', () => {
|
test('resolve dynamic component should fallback to plain element without warning', () => {
|
||||||
|
@ -6,13 +6,7 @@ import {
|
|||||||
ComponentOptions
|
ComponentOptions
|
||||||
} from '../component'
|
} from '../component'
|
||||||
import { Directive } from '../directives'
|
import { Directive } from '../directives'
|
||||||
import {
|
import { camelize, capitalize, isString, isObject } from '@vue/shared'
|
||||||
camelize,
|
|
||||||
capitalize,
|
|
||||||
isString,
|
|
||||||
isObject,
|
|
||||||
isFunction
|
|
||||||
} from '@vue/shared'
|
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
|
|
||||||
const COMPONENTS = 'components'
|
const COMPONENTS = 'components'
|
||||||
@ -22,14 +16,16 @@ export function resolveComponent(name: string): Component | string | undefined {
|
|||||||
return resolveAsset(COMPONENTS, name) || name
|
return resolveAsset(COMPONENTS, name) || name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const NULL_DYNAMIC_COMPONENT = Symbol()
|
||||||
|
|
||||||
export function resolveDynamicComponent(
|
export function resolveDynamicComponent(
|
||||||
component: unknown
|
component: unknown
|
||||||
): Component | string | undefined {
|
): Component | string | typeof NULL_DYNAMIC_COMPONENT {
|
||||||
if (!component) return
|
|
||||||
if (isString(component)) {
|
if (isString(component)) {
|
||||||
return resolveAsset(COMPONENTS, component, false) || component
|
return resolveAsset(COMPONENTS, component, false) || component
|
||||||
} else if (isFunction(component) || isObject(component)) {
|
} else {
|
||||||
return component
|
// invalid types will fallthrough to createVNode and raise warning
|
||||||
|
return (component as any) || NULL_DYNAMIC_COMPONENT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import { currentScopeId } from './helpers/scopeId'
|
|||||||
import { TeleportImpl, isTeleport } from './components/Teleport'
|
import { TeleportImpl, isTeleport } from './components/Teleport'
|
||||||
import { currentRenderingInstance } from './componentRenderUtils'
|
import { currentRenderingInstance } from './componentRenderUtils'
|
||||||
import { RendererNode, RendererElement } from './renderer'
|
import { RendererNode, RendererElement } from './renderer'
|
||||||
|
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
||||||
|
|
||||||
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
||||||
__isFragment: true
|
__isFragment: true
|
||||||
@ -254,15 +255,15 @@ export const createVNode = (__DEV__
|
|||||||
: _createVNode) as typeof _createVNode
|
: _createVNode) as typeof _createVNode
|
||||||
|
|
||||||
function _createVNode(
|
function _createVNode(
|
||||||
type: VNodeTypes | ClassComponent,
|
type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
|
||||||
props: (Data & VNodeProps) | null = null,
|
props: (Data & VNodeProps) | null = null,
|
||||||
children: unknown = null,
|
children: unknown = null,
|
||||||
patchFlag: number = 0,
|
patchFlag: number = 0,
|
||||||
dynamicProps: string[] | null = null,
|
dynamicProps: string[] | null = null,
|
||||||
isBlockNode = false
|
isBlockNode = false
|
||||||
): VNode {
|
): VNode {
|
||||||
if (!type) {
|
if (!type || type === NULL_DYNAMIC_COMPONENT) {
|
||||||
if (__DEV__) {
|
if (__DEV__ && !type) {
|
||||||
warn(`Invalid vnode type when creating vnode: ${type}.`)
|
warn(`Invalid vnode type when creating vnode: ${type}.`)
|
||||||
}
|
}
|
||||||
type = Comment
|
type = Comment
|
||||||
|
Loading…
Reference in New Issue
Block a user