refactor: move template ref setter into dedicated file
This commit is contained in:
parent
41c18effea
commit
1928c9b537
@ -8,7 +8,13 @@ import {
|
||||
getComponentName,
|
||||
ComponentOptions
|
||||
} from '../component'
|
||||
import { VNode, cloneVNode, isVNode, VNodeProps } from '../vnode'
|
||||
import {
|
||||
VNode,
|
||||
cloneVNode,
|
||||
isVNode,
|
||||
VNodeProps,
|
||||
invokeVNodeHook
|
||||
} from '../vnode'
|
||||
import { warn } from '../warning'
|
||||
import {
|
||||
onBeforeUnmount,
|
||||
@ -30,8 +36,7 @@ import {
|
||||
queuePostRenderEffect,
|
||||
MoveType,
|
||||
RendererElement,
|
||||
RendererNode,
|
||||
invokeVNodeHook
|
||||
RendererNode
|
||||
} from '../renderer'
|
||||
import { setTransitionHooks } from './BaseTransition'
|
||||
import { ComponentRenderContext } from '../componentPublicInstance'
|
||||
|
@ -7,14 +7,16 @@ import {
|
||||
Fragment,
|
||||
VNodeHook,
|
||||
createVNode,
|
||||
createTextVNode
|
||||
createTextVNode,
|
||||
invokeVNodeHook
|
||||
} from './vnode'
|
||||
import { flushPostFlushCbs } from './scheduler'
|
||||
import { ComponentInternalInstance } from './component'
|
||||
import { invokeDirectiveHook } from './directives'
|
||||
import { warn } from './warning'
|
||||
import { PatchFlags, ShapeFlags, isReservedProp, isOn } from '@vue/shared'
|
||||
import { RendererInternals, invokeVNodeHook, setRef } from './renderer'
|
||||
import { RendererInternals } from './renderer'
|
||||
import { setRef } from './rendererTemplateRef'
|
||||
import {
|
||||
SuspenseImpl,
|
||||
SuspenseBoundary,
|
||||
|
@ -9,17 +9,15 @@ import {
|
||||
createVNode,
|
||||
isSameVNodeType,
|
||||
Static,
|
||||
VNodeNormalizedRef,
|
||||
VNodeHook,
|
||||
VNodeNormalizedRefAtom,
|
||||
VNodeProps
|
||||
VNodeProps,
|
||||
invokeVNodeHook
|
||||
} from './vnode'
|
||||
import {
|
||||
ComponentInternalInstance,
|
||||
ComponentOptions,
|
||||
createComponentInstance,
|
||||
Data,
|
||||
getExposeProxy,
|
||||
setupComponent
|
||||
} from './component'
|
||||
import {
|
||||
@ -29,19 +27,15 @@ import {
|
||||
updateHOCHostEl
|
||||
} from './componentRenderUtils'
|
||||
import {
|
||||
isString,
|
||||
EMPTY_OBJ,
|
||||
EMPTY_ARR,
|
||||
isReservedProp,
|
||||
isFunction,
|
||||
PatchFlags,
|
||||
ShapeFlags,
|
||||
NOOP,
|
||||
hasOwn,
|
||||
invokeArrayFns,
|
||||
isArray,
|
||||
getGlobalThis,
|
||||
remove
|
||||
getGlobalThis
|
||||
} from '@vue/shared'
|
||||
import {
|
||||
queueJob,
|
||||
@ -51,16 +45,12 @@ import {
|
||||
flushPreFlushCbs,
|
||||
SchedulerJob
|
||||
} from './scheduler'
|
||||
import {
|
||||
isRef,
|
||||
pauseTracking,
|
||||
resetTracking,
|
||||
ReactiveEffect
|
||||
} from '@vue/reactivity'
|
||||
import { pauseTracking, resetTracking, ReactiveEffect } from '@vue/reactivity'
|
||||
import { updateProps } from './componentProps'
|
||||
import { updateSlots } from './componentSlots'
|
||||
import { pushWarningContext, popWarningContext, warn } from './warning'
|
||||
import { createAppAPI, CreateAppFunction } from './apiCreateApp'
|
||||
import { setRef } from './rendererTemplateRef'
|
||||
import {
|
||||
SuspenseBoundary,
|
||||
queueEffectWithSuspense,
|
||||
@ -69,11 +59,6 @@ import {
|
||||
import { TeleportImpl, TeleportVNode } from './components/Teleport'
|
||||
import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
|
||||
import { registerHMR, unregisterHMR, isHmrUpdating } from './hmr'
|
||||
import {
|
||||
ErrorCodes,
|
||||
callWithErrorHandling,
|
||||
callWithAsyncErrorHandling
|
||||
} from './errorHandling'
|
||||
import { createHydrationFunctions, RootHydrateFunction } from './hydration'
|
||||
import { invokeDirectiveHook } from './directives'
|
||||
import { startMeasure, endMeasure } from './profiling'
|
||||
@ -2351,124 +2336,6 @@ function baseCreateRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
export function setRef(
|
||||
rawRef: VNodeNormalizedRef,
|
||||
oldRawRef: VNodeNormalizedRef | null,
|
||||
parentSuspense: SuspenseBoundary | null,
|
||||
vnode: VNode,
|
||||
isUnmount = false
|
||||
) {
|
||||
if (isArray(rawRef)) {
|
||||
rawRef.forEach((r, i) =>
|
||||
setRef(
|
||||
r,
|
||||
oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef),
|
||||
parentSuspense,
|
||||
vnode,
|
||||
isUnmount
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (isAsyncWrapper(vnode) && !isUnmount) {
|
||||
// when mounting async components, nothing needs to be done,
|
||||
// because the template ref is forwarded to inner component
|
||||
return
|
||||
}
|
||||
|
||||
const refValue =
|
||||
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
|
||||
? getExposeProxy(vnode.component!) || vnode.component!.proxy
|
||||
: vnode.el
|
||||
const value = isUnmount ? null : refValue
|
||||
|
||||
const { i: owner, r: ref } = rawRef
|
||||
if (__DEV__ && !owner) {
|
||||
warn(
|
||||
`Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
|
||||
`A vnode with ref must be created inside the render function.`
|
||||
)
|
||||
return
|
||||
}
|
||||
const oldRef = oldRawRef && (oldRawRef as VNodeNormalizedRefAtom).r
|
||||
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
|
||||
const setupState = owner.setupState
|
||||
|
||||
// dynamic ref changed. unset old ref
|
||||
if (oldRef != null && oldRef !== ref) {
|
||||
if (isString(oldRef)) {
|
||||
refs[oldRef] = null
|
||||
if (hasOwn(setupState, oldRef)) {
|
||||
setupState[oldRef] = null
|
||||
}
|
||||
} else if (isRef(oldRef)) {
|
||||
oldRef.value = null
|
||||
}
|
||||
}
|
||||
|
||||
if (isFunction(ref)) {
|
||||
callWithErrorHandling(ref, owner, ErrorCodes.FUNCTION_REF, [value, refs])
|
||||
} else {
|
||||
const _isString = isString(ref)
|
||||
const _isRef = isRef(ref)
|
||||
if (_isString || _isRef) {
|
||||
const doSet = () => {
|
||||
if (rawRef.f) {
|
||||
const existing = _isString ? refs[ref] : ref.value
|
||||
if (isUnmount) {
|
||||
isArray(existing) && remove(existing, refValue)
|
||||
} else {
|
||||
if (!isArray(existing)) {
|
||||
if (_isString) {
|
||||
refs[ref] = [refValue]
|
||||
} else {
|
||||
ref.value = [refValue]
|
||||
if (rawRef.k) refs[rawRef.k] = ref.value
|
||||
}
|
||||
} else if (!existing.includes(refValue)) {
|
||||
existing.push(refValue)
|
||||
}
|
||||
}
|
||||
} else if (_isString) {
|
||||
refs[ref] = value
|
||||
if (hasOwn(setupState, ref)) {
|
||||
setupState[ref] = value
|
||||
}
|
||||
} else if (isRef(ref)) {
|
||||
ref.value = value
|
||||
if (rawRef.k) refs[rawRef.k] = value
|
||||
} else if (__DEV__) {
|
||||
warn('Invalid template ref type:', ref, `(${typeof ref})`)
|
||||
}
|
||||
}
|
||||
if (value) {
|
||||
// #1789: for non-null values, set them after render
|
||||
// null values means this is unmount and it should not overwrite another
|
||||
// ref with the same key
|
||||
;(doSet as SchedulerJob).id = -1
|
||||
queuePostRenderEffect(doSet, parentSuspense)
|
||||
} else {
|
||||
doSet()
|
||||
}
|
||||
} else if (__DEV__) {
|
||||
warn('Invalid template ref type:', ref, `(${typeof ref})`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function invokeVNodeHook(
|
||||
hook: VNodeHook,
|
||||
instance: ComponentInternalInstance | null,
|
||||
vnode: VNode,
|
||||
prevVNode: VNode | null = null
|
||||
) {
|
||||
callWithAsyncErrorHandling(hook, instance, ErrorCodes.VNODE_HOOK, [
|
||||
vnode,
|
||||
prevVNode
|
||||
])
|
||||
}
|
||||
|
||||
function toggleRecurse(
|
||||
{ effect, update }: ComponentInternalInstance,
|
||||
allowed: boolean
|
||||
|
127
packages/runtime-core/src/rendererTemplateRef.ts
Normal file
127
packages/runtime-core/src/rendererTemplateRef.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import { SuspenseBoundary } from './components/Suspense'
|
||||
import { VNode, VNodeNormalizedRef, VNodeNormalizedRefAtom } from './vnode'
|
||||
import {
|
||||
EMPTY_OBJ,
|
||||
hasOwn,
|
||||
isArray,
|
||||
isFunction,
|
||||
isString,
|
||||
remove,
|
||||
ShapeFlags
|
||||
} from '@vue/shared'
|
||||
import { isAsyncWrapper } from './apiAsyncComponent'
|
||||
import { getExposeProxy } from './component'
|
||||
import { warn } from './warning'
|
||||
import { isRef } from '@vue/reactivity'
|
||||
import { callWithErrorHandling, ErrorCodes } from './errorHandling'
|
||||
import { SchedulerJob } from './scheduler'
|
||||
import { queuePostRenderEffect } from './renderer'
|
||||
|
||||
/**
|
||||
* Function for handling a template ref
|
||||
*/
|
||||
export function setRef(
|
||||
rawRef: VNodeNormalizedRef,
|
||||
oldRawRef: VNodeNormalizedRef | null,
|
||||
parentSuspense: SuspenseBoundary | null,
|
||||
vnode: VNode,
|
||||
isUnmount = false
|
||||
) {
|
||||
if (isArray(rawRef)) {
|
||||
rawRef.forEach((r, i) =>
|
||||
setRef(
|
||||
r,
|
||||
oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef),
|
||||
parentSuspense,
|
||||
vnode,
|
||||
isUnmount
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (isAsyncWrapper(vnode) && !isUnmount) {
|
||||
// when mounting async components, nothing needs to be done,
|
||||
// because the template ref is forwarded to inner component
|
||||
return
|
||||
}
|
||||
|
||||
const refValue =
|
||||
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
|
||||
? getExposeProxy(vnode.component!) || vnode.component!.proxy
|
||||
: vnode.el
|
||||
const value = isUnmount ? null : refValue
|
||||
|
||||
const { i: owner, r: ref } = rawRef
|
||||
if (__DEV__ && !owner) {
|
||||
warn(
|
||||
`Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
|
||||
`A vnode with ref must be created inside the render function.`
|
||||
)
|
||||
return
|
||||
}
|
||||
const oldRef = oldRawRef && (oldRawRef as VNodeNormalizedRefAtom).r
|
||||
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
|
||||
const setupState = owner.setupState
|
||||
|
||||
// dynamic ref changed. unset old ref
|
||||
if (oldRef != null && oldRef !== ref) {
|
||||
if (isString(oldRef)) {
|
||||
refs[oldRef] = null
|
||||
if (hasOwn(setupState, oldRef)) {
|
||||
setupState[oldRef] = null
|
||||
}
|
||||
} else if (isRef(oldRef)) {
|
||||
oldRef.value = null
|
||||
}
|
||||
}
|
||||
|
||||
if (isFunction(ref)) {
|
||||
callWithErrorHandling(ref, owner, ErrorCodes.FUNCTION_REF, [value, refs])
|
||||
} else {
|
||||
const _isString = isString(ref)
|
||||
const _isRef = isRef(ref)
|
||||
if (_isString || _isRef) {
|
||||
const doSet = () => {
|
||||
if (rawRef.f) {
|
||||
const existing = _isString ? refs[ref] : ref.value
|
||||
if (isUnmount) {
|
||||
isArray(existing) && remove(existing, refValue)
|
||||
} else {
|
||||
if (!isArray(existing)) {
|
||||
if (_isString) {
|
||||
refs[ref] = [refValue]
|
||||
} else {
|
||||
ref.value = [refValue]
|
||||
if (rawRef.k) refs[rawRef.k] = ref.value
|
||||
}
|
||||
} else if (!existing.includes(refValue)) {
|
||||
existing.push(refValue)
|
||||
}
|
||||
}
|
||||
} else if (_isString) {
|
||||
refs[ref] = value
|
||||
if (hasOwn(setupState, ref)) {
|
||||
setupState[ref] = value
|
||||
}
|
||||
} else if (isRef(ref)) {
|
||||
ref.value = value
|
||||
if (rawRef.k) refs[rawRef.k] = value
|
||||
} else if (__DEV__) {
|
||||
warn('Invalid template ref type:', ref, `(${typeof ref})`)
|
||||
}
|
||||
}
|
||||
if (value) {
|
||||
// #1789: for non-null values, set them after render
|
||||
// null values means this is unmount and it should not overwrite another
|
||||
// ref with the same key
|
||||
;(doSet as SchedulerJob).id = -1
|
||||
queuePostRenderEffect(doSet, parentSuspense)
|
||||
} else {
|
||||
doSet()
|
||||
}
|
||||
} else if (__DEV__) {
|
||||
warn('Invalid template ref type:', ref, `(${typeof ref})`)
|
||||
}
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ import { hmrDirtyComponents } from './hmr'
|
||||
import { convertLegacyComponent } from './compat/component'
|
||||
import { convertLegacyVModelProps } from './compat/componentVModel'
|
||||
import { defineLegacyVNodeProperties } from './compat/renderFn'
|
||||
import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
|
||||
|
||||
export const Fragment = Symbol(__DEV__ ? 'Fragment' : undefined) as any as {
|
||||
__isFragment: true
|
||||
@ -811,3 +812,15 @@ export function mergeProps(...args: (Data & VNodeProps)[]) {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
export function invokeVNodeHook(
|
||||
hook: VNodeHook,
|
||||
instance: ComponentInternalInstance | null,
|
||||
vnode: VNode,
|
||||
prevVNode: VNode | null = null
|
||||
) {
|
||||
callWithAsyncErrorHandling(hook, instance, ErrorCodes.VNODE_HOOK, [
|
||||
vnode,
|
||||
prevVNode
|
||||
])
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user