vue3-yuanma/packages/runtime-core/src/h.ts
Evan You d901b6bea8 refactor(reactivity): use more efficient reactive checks
WeakSets and WeakMaps shows degrading performance as the amount of
observed objects increases. Using hidden keys result in better
performance especially when repeatedly creating large amounts of
reactive proxies.

This also makes it possible to more efficiently declare non-reactive
objects in userland.
2020-05-02 16:58:17 -04:00

155 lines
4.1 KiB
TypeScript

import {
VNode,
VNodeProps,
createVNode,
VNodeArrayChildren,
Fragment,
isVNode
} from './vnode'
import { Teleport, TeleportProps } from './components/Teleport'
import { Suspense, SuspenseProps } from './components/Suspense'
import { isObject, isArray } from '@vue/shared'
import { RawSlots } from './componentSlots'
import { FunctionalComponent, Component } from './component'
import { ComponentOptions } from './componentOptions'
// `h` is a more user-friendly version of `createVNode` that allows omitting the
// props when possible. It is intended for manually written render functions.
// Compiler-generated code uses `createVNode` because
// 1. it is monomorphic and avoids the extra call overhead
// 2. it allows specifying patchFlags for optimization
/*
// type only
h('div')
// type + props
h('div', {})
// type + omit props + children
// Omit props does NOT support named slots
h('div', []) // array
h('div', 'foo') // text
h('div', h('br')) // vnode
h(Component, () => {}) // default slot
// type + props + children
h('div', {}, []) // array
h('div', {}, 'foo') // text
h('div', {}, h('br')) // vnode
h(Component, {}, () => {}) // default slot
h(Component, {}, {}) // named slots
// named slots without props requires explicit `null` to avoid ambiguity
h(Component, null, {})
**/
type RawProps = VNodeProps & {
// used to differ from a single VNode object as children
__v_isVNode?: never
// used to differ from Array children
[Symbol.iterator]?: never
}
type RawChildren =
| string
| number
| boolean
| VNode
| VNodeArrayChildren
| (() => any)
// fake constructor type returned from `defineComponent`
interface Constructor<P = any> {
__isFragment?: never
__isTeleport?: never
__isSuspense?: never
new (): { $props: P }
}
// Excludes Component type from returned `defineComponent`
type NotDefinedComponent<T extends Component> = T extends Constructor
? never
: T
// The following is a series of overloads for providing props validation of
// manually written render functions.
// element
export function h(type: string, children?: RawChildren): VNode
export function h(
type: string,
props?: RawProps | null,
children?: RawChildren
): VNode
// fragment
export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode
export function h(
type: typeof Fragment,
props?: RawProps | null,
children?: VNodeArrayChildren
): VNode
// teleport (target prop is required)
export function h(
type: typeof Teleport,
props: RawProps & TeleportProps,
children: RawChildren
): VNode
// suspense
export function h(type: typeof Suspense, children?: RawChildren): VNode
export function h(
type: typeof Suspense,
props?: (RawProps & SuspenseProps) | null,
children?: RawChildren | RawSlots
): VNode
// functional component
export function h<P>(
type: FunctionalComponent<P>,
props?: (RawProps & P) | ({} extends P ? null : never),
children?: RawChildren | RawSlots
): VNode
// catch-all for generic component types
export function h(type: Component, children?: RawChildren): VNode
// exclude `defineComponent`
export function h<Options extends ComponentOptions | FunctionalComponent<{}>>(
type: NotDefinedComponent<Options>,
props?: RawProps | null,
children?: RawChildren | RawSlots
): VNode
// fake constructor type returned by `defineComponent` or class component
export function h(type: Constructor, children?: RawChildren): VNode
export function h<P>(
type: Constructor<P>,
props?: (RawProps & P) | ({} extends P ? null : never),
children?: RawChildren | RawSlots
): VNode
// Actual implementation
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
if (arguments.length === 2) {
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
// single vnode without props
if (isVNode(propsOrChildren)) {
return createVNode(type, null, [propsOrChildren])
}
// props without children
return createVNode(type, propsOrChildren)
} else {
// omit props
return createVNode(type, null, propsOrChildren)
}
} else {
if (isVNode(children)) {
children = [children]
}
return createVNode(type, propsOrChildren, children)
}
}