}
export function cleanup(effect: ReactiveEffect) {
- for (let i = 0; i < effect.deps.length; i++) {
- effect.deps[i].delete(effect)
+ const { deps } = effect
+ if (deps.length) {
+ for (let i = 0; i < deps.length; i++) {
+ deps[i].delete(effect)
+ }
+ deps.length = 0
}
- effect.deps.length = 0
}
export function track(
observable,
immutable
} from '@vue/observer'
-import { isFunction, EMPTY_OBJ } from '@vue/shared'
+import { EMPTY_OBJ } from '@vue/shared'
import { RenderProxyHandlers } from './componentProxy'
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
import { PROPS, DYNAMIC_SLOTS, FULL_PROPS } from './patchFlags'
import { Slots } from './componentSlots'
+import { STATEFUL_COMPONENT } from './shapeFlags'
export type Data = { [key: string]: any }
}
export function renderComponentRoot(instance: ComponentInstance): VNode {
- const { type: Component, renderProxy } = instance
- if (isFunction(Component)) {
- return normalizeVNode(Component(instance))
- } else {
- if (__DEV__ && !Component.render) {
+ const { type: Component, vnode } = instance
+ if (vnode.shapeFlag & STATEFUL_COMPONENT) {
+ if (__DEV__ && !(Component as any).render) {
// TODO warn missing render
}
return normalizeVNode(
- (Component.render as Function).call(renderProxy, instance)
+ (Component as any).render.call(instance.renderProxy, instance)
)
+ } else {
+ // functional
+ return normalizeVNode((Component as FunctionalComponent)(instance))
}
}
createComponentInstance,
setupStatefulComponent
} from './component'
-import {
- isString,
- isArray,
- isFunction,
- isObject,
- EMPTY_OBJ,
- EMPTY_ARR
-} from '@vue/shared'
+import { isString, isArray, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
import {
TEXT,
CLASS,
import { effect, stop, ReactiveEffectOptions } from '@vue/observer'
import { resolveProps } from './componentProps'
import { resolveSlots } from './componentSlots'
+import { ELEMENT, STATEFUL_COMPONENT, FUNCTIONAL_COMPONENT } from './shapeFlags'
const prodEffectOptions = {
scheduler: queueJob
n2: VNode,
container: HostNode,
anchor?: HostNode,
- optimized?: boolean
+ optimized: boolean = false
) {
// patching & not same type, unmount old tree
if (n1 != null && !isSameType(n1, n2)) {
n1 = null
}
- const { type } = n2
+ const { type, shapeFlag } = n2
switch (type) {
case Text:
processText(n1, n2, container, anchor)
processPortal(n1, n2, container, anchor, optimized)
break
default:
- if (isString(type)) {
+ if (shapeFlag & ELEMENT) {
processElement(n1, n2, container, anchor, optimized)
} else {
- if (__DEV__ && !isFunction(type) && !isObject(type)) {
+ if (
+ __DEV__ &&
+ !(shapeFlag & STATEFUL_COMPONENT) &&
+ !(shapeFlag & FUNCTIONAL_COMPONENT)
+ ) {
// TODO warn invalid node type
debugger
}
const instance: ComponentInstance = (vnode.component = createComponentInstance(
Component
))
- instance.update = effect(() => {
- if (!instance.vnode) {
+ instance.update = effect(function updateComponent() {
+ if (instance.vnode === null) {
// initial mount
instance.vnode = vnode
resolveProps(instance, vnode.props, Component.props)
resolveSlots(instance, vnode.children)
// setup stateful
- if (typeof Component === 'object') {
+ if (vnode.shapeFlag & STATEFUL_COMPONENT) {
setupStatefulComponent(instance)
}
const subTree = (instance.subTree = renderComponentRoot(instance))
--- /dev/null
+export const ELEMENT = 1
+export const FUNCTIONAL_COMPONENT = 1 << 1
+export const STATEFUL_COMPONENT = 1 << 2
import { HostNode } from './createRenderer'
import { RawSlots } from './componentSlots'
import { CLASS } from './patchFlags'
+import { ELEMENT, FUNCTIONAL_COMPONENT, STATEFUL_COMPONENT } from './shapeFlags'
export const Fragment = Symbol('Fragment')
export const Text = Symbol('Text')
target: HostNode | null // portal target
// optimization only
+ shapeFlag: number
patchFlag: number
dynamicProps: string[] | null
dynamicChildren: VNode[] | null
): VNode {
// Allow passing 0 for props, this can save bytes on generated code.
props = props || null
+
+ const shapeFlag = isString(type)
+ ? ELEMENT
+ : isFunction(type)
+ ? FUNCTIONAL_COMPONENT
+ : isObject(type)
+ ? STATEFUL_COMPONENT
+ : 0
+
const vnode: VNode = {
type,
props,
el: null,
anchor: null,
target: null,
+ shapeFlag,
patchFlag,
dynamicProps,
dynamicChildren: null
// component nodes also should always be tracked, because even if the
// component doesn't need to update, it needs to persist the instance on to
// the next vnode so that it can be properly unmounted later.
- if (shouldTrack && (patchFlag || isObject(type) || isFunction(type))) {
+ if (
+ shouldTrack &&
+ (patchFlag ||
+ shapeFlag & STATEFUL_COMPONENT ||
+ shapeFlag & FUNCTIONAL_COMPONENT)
+ ) {
trackDynamicNode(vnode)
}