diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 243bde548c5..9d97bb18593 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -562,3 +562,7 @@ export { initFeatureFlags } from './featureFlags' * @internal */ export { createInternalObject } from './internalObject' +/** + * @internal + */ +export { createCanSetSetupRefChecker } from './rendererTemplateRef' diff --git a/packages/runtime-core/src/rendererTemplateRef.ts b/packages/runtime-core/src/rendererTemplateRef.ts index 31fcf8c2d5b..84f0bda1b95 100644 --- a/packages/runtime-core/src/rendererTemplateRef.ts +++ b/packages/runtime-core/src/rendererTemplateRef.ts @@ -14,7 +14,11 @@ import { warn } from './warning' import { isRef, toRaw } from '@vue/reactivity' import { ErrorCodes, callWithErrorHandling } from './errorHandling' import { queuePostRenderEffect } from './renderer' -import { type ComponentOptions, getComponentPublicInstance } from './component' +import { + type ComponentOptions, + type Data, + getComponentPublicInstance, +} from './component' import { knownTemplateRefs } from './helpers/useTemplateRef' /** @@ -73,25 +77,7 @@ export function setRef( 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) => { - if (__DEV__) { - if (hasOwn(rawSetupState, key) && !isRef(rawSetupState[key])) { - warn( - `Template ref "${key}" used on a non-ref value. ` + - `It will not work in the production build.`, - ) - } - - if (knownTemplateRefs.has(rawSetupState[key] as any)) { - return false - } - } - return hasOwn(rawSetupState, key) - } + const canSetSetupRef = createCanSetSetupRefChecker(setupState) // dynamic ref changed. unset old ref if (oldRef != null && oldRef !== ref) { @@ -161,3 +147,26 @@ export function setRef( } } } + +export function createCanSetSetupRefChecker( + setupState: Data, +): (key: string) => boolean { + const rawSetupState = toRaw(setupState) + return setupState === EMPTY_OBJ + ? () => false + : (key: string) => { + if (__DEV__) { + if (hasOwn(rawSetupState, key) && !isRef(rawSetupState[key])) { + warn( + `Template ref "${key}" used on a non-ref value. ` + + `It will not work in the production build.`, + ) + } + + if (knownTemplateRefs.has(rawSetupState[key] as any)) { + return false + } + } + return hasOwn(rawSetupState, key) + } +} diff --git a/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts b/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts index f1ce23ac156..4e8a1a9253c 100644 --- a/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts +++ b/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts @@ -19,6 +19,7 @@ import { nextTick, reactive, ref, + shallowRef, useTemplateRef, watchEffect, } from '@vue/runtime-dom' @@ -208,8 +209,8 @@ describe('api: template ref', () => { const { render } = define({ setup() { return { - foo: fooEl, - bar: barEl, + foo: shallowRef(fooEl), + bar: shallowRef(barEl), } }, render() { @@ -251,6 +252,7 @@ describe('api: template ref', () => { }) const { host } = render() expect(state.refKey).toBe(host.children[0]) + expect('Template ref "refKey" used on a non-ref value').toHaveBeenWarned() }) test('multiple root refs', () => { @@ -713,6 +715,45 @@ describe('api: template ref', () => { expect(html()).toBe('