Skip to content

Commit 1928c9b

Browse files
committed
refactor: move template ref setter into dedicated file
1 parent 41c18ef commit 1928c9b

File tree

6 files changed

+157
-143
lines changed

6 files changed

+157
-143
lines changed

packages/runtime-core/src/components/KeepAlive.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import {
88
getComponentName,
99
ComponentOptions
1010
} from '../component'
11-
import { VNode, cloneVNode, isVNode, VNodeProps } from '../vnode'
11+
import {
12+
VNode,
13+
cloneVNode,
14+
isVNode,
15+
VNodeProps,
16+
invokeVNodeHook
17+
} from '../vnode'
1218
import { warn } from '../warning'
1319
import {
1420
onBeforeUnmount,
@@ -30,8 +36,7 @@ import {
3036
queuePostRenderEffect,
3137
MoveType,
3238
RendererElement,
33-
RendererNode,
34-
invokeVNodeHook
39+
RendererNode
3540
} from '../renderer'
3641
import { setTransitionHooks } from './BaseTransition'
3742
import { ComponentRenderContext } from '../componentPublicInstance'

packages/runtime-core/src/hydration.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import {
77
Fragment,
88
VNodeHook,
99
createVNode,
10-
createTextVNode
10+
createTextVNode,
11+
invokeVNodeHook
1112
} from './vnode'
1213
import { flushPostFlushCbs } from './scheduler'
1314
import { ComponentInternalInstance } from './component'
1415
import { invokeDirectiveHook } from './directives'
1516
import { warn } from './warning'
1617
import { PatchFlags, ShapeFlags, isReservedProp, isOn } from '@vue/shared'
17-
import { RendererInternals, invokeVNodeHook, setRef } from './renderer'
18+
import { RendererInternals } from './renderer'
19+
import { setRef } from './rendererTemplateRef'
1820
import {
1921
SuspenseImpl,
2022
SuspenseBoundary,

packages/runtime-core/src/renderer.ts

Lines changed: 5 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@ import {
99
createVNode,
1010
isSameVNodeType,
1111
Static,
12-
VNodeNormalizedRef,
1312
VNodeHook,
14-
VNodeNormalizedRefAtom,
15-
VNodeProps
13+
VNodeProps,
14+
invokeVNodeHook
1615
} from './vnode'
1716
import {
1817
ComponentInternalInstance,
1918
ComponentOptions,
2019
createComponentInstance,
2120
Data,
22-
getExposeProxy,
2321
setupComponent
2422
} from './component'
2523
import {
@@ -29,19 +27,15 @@ import {
2927
updateHOCHostEl
3028
} from './componentRenderUtils'
3129
import {
32-
isString,
3330
EMPTY_OBJ,
3431
EMPTY_ARR,
3532
isReservedProp,
36-
isFunction,
3733
PatchFlags,
3834
ShapeFlags,
3935
NOOP,
40-
hasOwn,
4136
invokeArrayFns,
4237
isArray,
43-
getGlobalThis,
44-
remove
38+
getGlobalThis
4539
} from '@vue/shared'
4640
import {
4741
queueJob,
@@ -51,16 +45,12 @@ import {
5145
flushPreFlushCbs,
5246
SchedulerJob
5347
} from './scheduler'
54-
import {
55-
isRef,
56-
pauseTracking,
57-
resetTracking,
58-
ReactiveEffect
59-
} from '@vue/reactivity'
48+
import { pauseTracking, resetTracking, ReactiveEffect } from '@vue/reactivity'
6049
import { updateProps } from './componentProps'
6150
import { updateSlots } from './componentSlots'
6251
import { pushWarningContext, popWarningContext, warn } from './warning'
6352
import { createAppAPI, CreateAppFunction } from './apiCreateApp'
53+
import { setRef } from './rendererTemplateRef'
6454
import {
6555
SuspenseBoundary,
6656
queueEffectWithSuspense,
@@ -69,11 +59,6 @@ import {
6959
import { TeleportImpl, TeleportVNode } from './components/Teleport'
7060
import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
7161
import { registerHMR, unregisterHMR, isHmrUpdating } from './hmr'
72-
import {
73-
ErrorCodes,
74-
callWithErrorHandling,
75-
callWithAsyncErrorHandling
76-
} from './errorHandling'
7762
import { createHydrationFunctions, RootHydrateFunction } from './hydration'
7863
import { invokeDirectiveHook } from './directives'
7964
import { startMeasure, endMeasure } from './profiling'
@@ -2351,124 +2336,6 @@ function baseCreateRenderer(
23512336
}
23522337
}
23532338

2354-
export function setRef(
2355-
rawRef: VNodeNormalizedRef,
2356-
oldRawRef: VNodeNormalizedRef | null,
2357-
parentSuspense: SuspenseBoundary | null,
2358-
vnode: VNode,
2359-
isUnmount = false
2360-
) {
2361-
if (isArray(rawRef)) {
2362-
rawRef.forEach((r, i) =>
2363-
setRef(
2364-
r,
2365-
oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef),
2366-
parentSuspense,
2367-
vnode,
2368-
isUnmount
2369-
)
2370-
)
2371-
return
2372-
}
2373-
2374-
if (isAsyncWrapper(vnode) && !isUnmount) {
2375-
// when mounting async components, nothing needs to be done,
2376-
// because the template ref is forwarded to inner component
2377-
return
2378-
}
2379-
2380-
const refValue =
2381-
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
2382-
? getExposeProxy(vnode.component!) || vnode.component!.proxy
2383-
: vnode.el
2384-
const value = isUnmount ? null : refValue
2385-
2386-
const { i: owner, r: ref } = rawRef
2387-
if (__DEV__ && !owner) {
2388-
warn(
2389-
`Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
2390-
`A vnode with ref must be created inside the render function.`
2391-
)
2392-
return
2393-
}
2394-
const oldRef = oldRawRef && (oldRawRef as VNodeNormalizedRefAtom).r
2395-
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
2396-
const setupState = owner.setupState
2397-
2398-
// dynamic ref changed. unset old ref
2399-
if (oldRef != null && oldRef !== ref) {
2400-
if (isString(oldRef)) {
2401-
refs[oldRef] = null
2402-
if (hasOwn(setupState, oldRef)) {
2403-
setupState[oldRef] = null
2404-
}
2405-
} else if (isRef(oldRef)) {
2406-
oldRef.value = null
2407-
}
2408-
}
2409-
2410-
if (isFunction(ref)) {
2411-
callWithErrorHandling(ref, owner, ErrorCodes.FUNCTION_REF, [value, refs])
2412-
} else {
2413-
const _isString = isString(ref)
2414-
const _isRef = isRef(ref)
2415-
if (_isString || _isRef) {
2416-
const doSet = () => {
2417-
if (rawRef.f) {
2418-
const existing = _isString ? refs[ref] : ref.value
2419-
if (isUnmount) {
2420-
isArray(existing) && remove(existing, refValue)
2421-
} else {
2422-
if (!isArray(existing)) {
2423-
if (_isString) {
2424-
refs[ref] = [refValue]
2425-
} else {
2426-
ref.value = [refValue]
2427-
if (rawRef.k) refs[rawRef.k] = ref.value
2428-
}
2429-
} else if (!existing.includes(refValue)) {
2430-
existing.push(refValue)
2431-
}
2432-
}
2433-
} else if (_isString) {
2434-
refs[ref] = value
2435-
if (hasOwn(setupState, ref)) {
2436-
setupState[ref] = value
2437-
}
2438-
} else if (isRef(ref)) {
2439-
ref.value = value
2440-
if (rawRef.k) refs[rawRef.k] = value
2441-
} else if (__DEV__) {
2442-
warn('Invalid template ref type:', ref, `(${typeof ref})`)
2443-
}
2444-
}
2445-
if (value) {
2446-
// #1789: for non-null values, set them after render
2447-
// null values means this is unmount and it should not overwrite another
2448-
// ref with the same key
2449-
;(doSet as SchedulerJob).id = -1
2450-
queuePostRenderEffect(doSet, parentSuspense)
2451-
} else {
2452-
doSet()
2453-
}
2454-
} else if (__DEV__) {
2455-
warn('Invalid template ref type:', ref, `(${typeof ref})`)
2456-
}
2457-
}
2458-
}
2459-
2460-
export function invokeVNodeHook(
2461-
hook: VNodeHook,
2462-
instance: ComponentInternalInstance | null,
2463-
vnode: VNode,
2464-
prevVNode: VNode | null = null
2465-
) {
2466-
callWithAsyncErrorHandling(hook, instance, ErrorCodes.VNODE_HOOK, [
2467-
vnode,
2468-
prevVNode
2469-
])
2470-
}
2471-
24722339
function toggleRecurse(
24732340
{ effect, update }: ComponentInternalInstance,
24742341
allowed: boolean
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { SuspenseBoundary } from './components/Suspense'
2+
import { VNode, VNodeNormalizedRef, VNodeNormalizedRefAtom } from './vnode'
3+
import {
4+
EMPTY_OBJ,
5+
hasOwn,
6+
isArray,
7+
isFunction,
8+
isString,
9+
remove,
10+
ShapeFlags
11+
} from '@vue/shared'
12+
import { isAsyncWrapper } from './apiAsyncComponent'
13+
import { getExposeProxy } from './component'
14+
import { warn } from './warning'
15+
import { isRef } from '@vue/reactivity'
16+
import { callWithErrorHandling, ErrorCodes } from './errorHandling'
17+
import { SchedulerJob } from './scheduler'
18+
import { queuePostRenderEffect } from './renderer'
19+
20+
/**
21+
* Function for handling a template ref
22+
*/
23+
export function setRef(
24+
rawRef: VNodeNormalizedRef,
25+
oldRawRef: VNodeNormalizedRef | null,
26+
parentSuspense: SuspenseBoundary | null,
27+
vnode: VNode,
28+
isUnmount = false
29+
) {
30+
if (isArray(rawRef)) {
31+
rawRef.forEach((r, i) =>
32+
setRef(
33+
r,
34+
oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef),
35+
parentSuspense,
36+
vnode,
37+
isUnmount
38+
)
39+
)
40+
return
41+
}
42+
43+
if (isAsyncWrapper(vnode) && !isUnmount) {
44+
// when mounting async components, nothing needs to be done,
45+
// because the template ref is forwarded to inner component
46+
return
47+
}
48+
49+
const refValue =
50+
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
51+
? getExposeProxy(vnode.component!) || vnode.component!.proxy
52+
: vnode.el
53+
const value = isUnmount ? null : refValue
54+
55+
const { i: owner, r: ref } = rawRef
56+
if (__DEV__ && !owner) {
57+
warn(
58+
`Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
59+
`A vnode with ref must be created inside the render function.`
60+
)
61+
return
62+
}
63+
const oldRef = oldRawRef && (oldRawRef as VNodeNormalizedRefAtom).r
64+
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
65+
const setupState = owner.setupState
66+
67+
// dynamic ref changed. unset old ref
68+
if (oldRef != null && oldRef !== ref) {
69+
if (isString(oldRef)) {
70+
refs[oldRef] = null
71+
if (hasOwn(setupState, oldRef)) {
72+
setupState[oldRef] = null
73+
}
74+
} else if (isRef(oldRef)) {
75+
oldRef.value = null
76+
}
77+
}
78+
79+
if (isFunction(ref)) {
80+
callWithErrorHandling(ref, owner, ErrorCodes.FUNCTION_REF, [value, refs])
81+
} else {
82+
const _isString = isString(ref)
83+
const _isRef = isRef(ref)
84+
if (_isString || _isRef) {
85+
const doSet = () => {
86+
if (rawRef.f) {
87+
const existing = _isString ? refs[ref] : ref.value
88+
if (isUnmount) {
89+
isArray(existing) && remove(existing, refValue)
90+
} else {
91+
if (!isArray(existing)) {
92+
if (_isString) {
93+
refs[ref] = [refValue]
94+
} else {
95+
ref.value = [refValue]
96+
if (rawRef.k) refs[rawRef.k] = ref.value
97+
}
98+
} else if (!existing.includes(refValue)) {
99+
existing.push(refValue)
100+
}
101+
}
102+
} else if (_isString) {
103+
refs[ref] = value
104+
if (hasOwn(setupState, ref)) {
105+
setupState[ref] = value
106+
}
107+
} else if (isRef(ref)) {
108+
ref.value = value
109+
if (rawRef.k) refs[rawRef.k] = value
110+
} else if (__DEV__) {
111+
warn('Invalid template ref type:', ref, `(${typeof ref})`)
112+
}
113+
}
114+
if (value) {
115+
// #1789: for non-null values, set them after render
116+
// null values means this is unmount and it should not overwrite another
117+
// ref with the same key
118+
;(doSet as SchedulerJob).id = -1
119+
queuePostRenderEffect(doSet, parentSuspense)
120+
} else {
121+
doSet()
122+
}
123+
} else if (__DEV__) {
124+
warn('Invalid template ref type:', ref, `(${typeof ref})`)
125+
}
126+
}
127+
}

packages/runtime-core/src/vnode.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { hmrDirtyComponents } from './hmr'
4242
import { convertLegacyComponent } from './compat/component'
4343
import { convertLegacyVModelProps } from './compat/componentVModel'
4444
import { defineLegacyVNodeProperties } from './compat/renderFn'
45+
import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
4546

4647
export const Fragment = Symbol(__DEV__ ? 'Fragment' : undefined) as any as {
4748
__isFragment: true
@@ -811,3 +812,15 @@ export function mergeProps(...args: (Data & VNodeProps)[]) {
811812
}
812813
return ret
813814
}
815+
816+
export function invokeVNodeHook(
817+
hook: VNodeHook,
818+
instance: ComponentInternalInstance | null,
819+
vnode: VNode,
820+
prevVNode: VNode | null = null
821+
) {
822+
callWithAsyncErrorHandling(hook, instance, ErrorCodes.VNODE_HOOK, [
823+
vnode,
824+
prevVNode
825+
])
826+
}

0 commit comments

Comments
 (0)