diff --git a/packages/runtime-core/__tests__/helpers/useTemplateRef.spec.ts b/packages/runtime-core/__tests__/helpers/useTemplateRef.spec.ts index adc8ed66c77..047df6b492b 100644 --- a/packages/runtime-core/__tests__/helpers/useTemplateRef.spec.ts +++ b/packages/runtime-core/__tests__/helpers/useTemplateRef.spec.ts @@ -3,6 +3,7 @@ import { h, nextTick, nodeOps, + onMounted, ref, render, useTemplateRef, @@ -125,4 +126,25 @@ describe('useTemplateRef', () => { __DEV__ = true } }) + + // #12749 + test(`don't update setup ref for useTemplateRef key`, () => { + let foo: ShallowRef + const Comp = { + setup() { + foo = useTemplateRef('bar') + const bar = ref(null) + onMounted(() => { + expect(bar.value).toBe(null) + }) + return { bar } + }, + render() { + return h('div', { ref: 'bar' }) + }, + } + const root = nodeOps.createElement('div') + render(h(Comp), root) + expect(foo!.value).toBe(root.children[0]) + }) }) diff --git a/packages/runtime-core/src/helpers/useTemplateRef.ts b/packages/runtime-core/src/helpers/useTemplateRef.ts index 4cb10ea8139..1a6c87ea816 100644 --- a/packages/runtime-core/src/helpers/useTemplateRef.ts +++ b/packages/runtime-core/src/helpers/useTemplateRef.ts @@ -1,5 +1,5 @@ import { type ShallowRef, readonly, shallowRef } from '@vue/reactivity' -import { getCurrentInstance } from '../component' +import { type Data, getCurrentInstance } from '../component' import { warn } from '../warning' import { EMPTY_OBJ } from '@vue/shared' @@ -12,12 +12,7 @@ export function useTemplateRef( const r = shallowRef(null) if (i) { const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs - let desc: PropertyDescriptor | undefined - if ( - __DEV__ && - (desc = Object.getOwnPropertyDescriptor(refs, key)) && - !desc.configurable - ) { + if (__DEV__ && isUseTemplateRefKey(refs, key)) { warn(`useTemplateRef('${key}') already exists.`) } else { Object.defineProperty(refs, key, { @@ -38,3 +33,10 @@ export function useTemplateRef( } return ret } + +export function isUseTemplateRefKey(refs: Data, key: string): boolean { + let desc: PropertyDescriptor | undefined + return !!( + (desc = Object.getOwnPropertyDescriptor(refs, key)) && !desc.configurable + ) +} diff --git a/packages/runtime-core/src/rendererTemplateRef.ts b/packages/runtime-core/src/rendererTemplateRef.ts index ca21030dc35..664cea6e687 100644 --- a/packages/runtime-core/src/rendererTemplateRef.ts +++ b/packages/runtime-core/src/rendererTemplateRef.ts @@ -16,7 +16,10 @@ import { ErrorCodes, callWithErrorHandling } from './errorHandling' import type { SchedulerJob } from './scheduler' import { queuePostRenderEffect } from './renderer' import { type ComponentOptions, getComponentPublicInstance } from './component' -import { knownTemplateRefs } from './helpers/useTemplateRef' +import { + isUseTemplateRefKey, + knownTemplateRefs, +} from './helpers/useTemplateRef' /** * Function for handling a template ref @@ -91,6 +94,12 @@ export function setRef( return false } } + + // skip setting up ref if the key is from useTemplateRef + if (isUseTemplateRefKey(refs, key)) { + return false + } + return hasOwn(rawSetupState, key) }