createComponentInstance,
setupStatefulComponent
} from './component'
-import { isString, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
+import {
+ isString,
+ EMPTY_OBJ,
+ EMPTY_ARR,
+ isReservedProp,
+ isFunction
+} from '@vue/shared'
import {
TEXT,
CLASS,
isSVG: boolean,
optimized: boolean
) {
- // mount
if (n1 == null) {
mountElement(n2, container, anchor, parentComponent, isSVG)
} else {
patchElement(n1, n2, parentComponent, isSVG, optimized)
}
+ if (n2.ref !== null && parentComponent !== null) {
+ setRef(n2.ref, parentComponent, n2.el)
+ }
}
function mountElement(
const { props, shapeFlag } = vnode
if (props != null) {
for (const key in props) {
+ if (isReservedProp(key)) continue
hostPatchProp(el, key, props[key], null, isSVG)
}
}
) {
if (oldProps !== newProps) {
for (const key in newProps) {
- if (key === 'key' || key === 'ref') continue
+ if (isReservedProp(key)) continue
const next = newProps[key]
const prev = oldProps[key]
if (next !== prev) {
}
if (oldProps !== EMPTY_OBJ) {
for (const key in oldProps) {
- if (key === 'key' || key === 'ref') continue
+ if (isReservedProp(key)) continue
if (!(key in newProps)) {
hostPatchProp(
el,
n2.el = n1.el
}
}
+ if (n2.ref !== null && parentComponent !== null) {
+ setRef(
+ n2.ref,
+ parentComponent,
+ (n2.component as ComponentInstance).renderProxy
+ )
+ }
}
function mountComponent(
Component,
parentComponent
))
- instance.update = effect(function updateComponent() {
+ instance.update = effect(function componentEffect() {
if (instance.vnode === null) {
- // initial mount
+ // mountComponent
instance.vnode = initialVNode
resolveProps(instance, initialVNode.props, Component.props)
resolveSlots(instance, initialVNode.children)
queuePostFlushCb(instance.m)
}
} else {
- // component update
+ // updateComponent
// This is triggered by mutation of component's own state (next: null)
// OR parent calling processComponent (next: VNode)
const { next } = instance
if (instance.bu !== null) {
invokeHooks(instance.bu)
}
+ // reset refs
+ // only needed if previous patch had refs
+ if (instance.refs !== EMPTY_OBJ) {
+ instance.refs = {}
+ }
patch(
prevTree,
nextTree,
- // may have moved
+ // parent may have changed if it's in a portal
hostParentNode(prevTree.el),
+ // anchor may have changed if it's in a fragment
getNextHostNode(prevTree),
instance,
isSVG
}
function move(vnode: VNode, container: HostNode, anchor: HostNode) {
- if (vnode.component != null) {
+ if (vnode.component !== null) {
move(vnode.component.subTree, container, anchor)
return
}
: getNextHostNode(vnode.component.subTree)
}
+ function setRef(
+ ref: string | Function,
+ parent: ComponentInstance,
+ value: HostNode | ComponentInstance
+ ) {
+ const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
+ if (isString(ref)) {
+ refs[ref] = value
+ } else {
+ if (__DEV__ && !isFunction(ref)) {
+ // TODO warn invalid ref type
+ }
+ ref(value, refs)
+ }
+ }
+
return function render(vnode: VNode | null, dom: HostNode): VNode | null {
if (vnode == null) {
if (dom._vnode) {
type: VNodeTypes
props: { [key: string]: any } | null
key: string | number | null
+ ref: string | Function | null
children: NormalizedChildren
component: ComponentInstance | null
// function render() {
// return (openBlock(),createBlock('div', null, [...]))
// }
+//
+// disableTracking is true when creating a fragment block, since a fragment
+// always diffs its children.
export function openBlock(disableTrackng?: boolean) {
blockStack.push(disableTrackng ? null : [])
}
type,
props,
key: props && props.key,
+ ref: props && props.ref,
children: null,
component: null,
el: null,