fix(runtime-vapor): fix readonly warning when useTemplateRef has same variable name as template ref

close #13665
This commit is contained in:
daiwei 2025-07-21 11:54:33 +08:00
parent 56a7f9dd18
commit 7b1b7cfb7f
3 changed files with 39 additions and 24 deletions

View File

@ -562,3 +562,7 @@ export { initFeatureFlags } from './featureFlags'
* @internal
*/
export { createInternalObject } from './internalObject'
/**
* @internal
*/
export { validateTemplateRef } from './rendererTemplateRef'

View File

@ -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 = validateTemplateRef(setupState)
// dynamic ref changed. unset old ref
if (oldRef != null && oldRef !== ref) {
@ -161,3 +147,26 @@ export function setRef(
}
}
}
export function validateTemplateRef(
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)
}
}

View File

@ -10,6 +10,7 @@ import {
type SchedulerJob,
callWithErrorHandling,
queuePostFlushCb,
validateTemplateRef,
warn,
} from '@vue/runtime-dom'
import {
@ -55,6 +56,7 @@ export function setRef(
const refs =
instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
const canSetSetupRef = validateTemplateRef(setupState)
// dynamic ref changed. unset old ref
if (oldRef != null && oldRef !== ref) {
if (isString(oldRef)) {
@ -87,7 +89,7 @@ export function setRef(
const doSet: SchedulerJob = () => {
if (refFor) {
existing = _isString
? __DEV__ && hasOwn(setupState, ref)
? __DEV__ && canSetSetupRef(ref)
? setupState[ref]
: refs[ref]
: ref.value
@ -96,7 +98,7 @@ export function setRef(
existing = [refValue]
if (_isString) {
refs[ref] = existing
if (__DEV__ && hasOwn(setupState, ref)) {
if (__DEV__ && canSetSetupRef(ref)) {
setupState[ref] = refs[ref]
// if setupState[ref] is a reactivity ref,
// the existing will also become reactivity too
@ -111,7 +113,7 @@ export function setRef(
}
} else if (_isString) {
refs[ref] = refValue
if (__DEV__ && hasOwn(setupState, ref)) {
if (__DEV__ && canSetSetupRef(ref)) {
setupState[ref] = refValue
}
} else if (_isRef) {
@ -129,7 +131,7 @@ export function setRef(
remove(existing, refValue)
} else if (_isString) {
refs[ref] = null
if (__DEV__ && hasOwn(setupState, ref)) {
if (__DEV__ && canSetSetupRef(ref)) {
setupState[ref] = null
}
} else if (_isRef) {