import {
+ type ShallowRef,
h,
nextTick,
nodeOps,
})
// #11795
- test('should work when variable name is same as key', () => {
- let tRef
+ test('should not attempt to set when variable name is same as key', () => {
+ let tRef: ShallowRef
const key = 'refKey'
const Comp = {
setup() {
- tRef = useTemplateRef(key)
+ tRef = useTemplateRef('_')
return {
[key]: tRef,
}
render(h(Comp), root)
expect('target is readonly').not.toHaveBeenWarned()
+ expect(tRef!.value).toBe(null)
+ })
+
+ test('should work when used as direct ref value (compiled in prod mode)', () => {
+ __DEV__ = false
+ try {
+ let foo: ShallowRef
+ const Comp = {
+ setup() {
+ foo = useTemplateRef('foo')
+ return () => h('div', { ref: foo })
+ },
+ }
+ const root = nodeOps.createElement('div')
+ render(h(Comp), root)
+
+ expect('target is readonly').not.toHaveBeenWarned()
+ expect(foo!.value).toBe(root.children[0])
+ } finally {
+ __DEV__ = true
+ }
})
})
import { warn } from '../warning'
import { EMPTY_OBJ } from '@vue/shared'
+export const knownTemplateRefs: WeakSet<ShallowRef> = new WeakSet()
+
export function useTemplateRef<T = unknown, Keys extends string = string>(
key: Keys,
): Readonly<ShallowRef<T | null>> {
const r = shallowRef(null)
if (i) {
const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs
-
let desc: PropertyDescriptor | undefined
if (
__DEV__ &&
`instance to be associated with.`,
)
}
- return (__DEV__ ? readonly(r) : r) as any
+ const ret = __DEV__ ? readonly(r) : r
+ if (__DEV__) {
+ knownTemplateRefs.add(ret)
+ }
+ return ret
}
} from '@vue/shared'
import { isAsyncWrapper } from './apiAsyncComponent'
import { warn } from './warning'
-import { isRef } from '@vue/reactivity'
+import { isRef, toRaw } from '@vue/reactivity'
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
import type { SchedulerJob } from './scheduler'
import { queuePostRenderEffect } from './renderer'
import { getComponentPublicInstance } from './component'
+import { knownTemplateRefs } from './helpers/useTemplateRef'
/**
* Function for handling a template ref
const oldRef = oldRawRef && (oldRawRef as VNodeNormalizedRefAtom).r
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
const setupState = owner.setupState
+ const rawSetupState = toRaw(setupState)
const canSetSetupRef =
setupState === EMPTY_OBJ
? () => false
- : (key: string) =>
- hasOwn(setupState, key) &&
- !(Object.getOwnPropertyDescriptor(refs, key) || EMPTY_OBJ).get
+ : (key: string) => {
+ if (__DEV__ && knownTemplateRefs.has(rawSetupState[key] as any)) {
+ return false
+ }
+ return hasOwn(rawSetupState, key)
+ }
// dynamic ref changed. unset old ref
if (oldRef != null && oldRef !== ref) {