diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 0f1a684dad0..493d08b5a05 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -379,10 +379,10 @@ export interface GenericComponentInstance { */ propsDefaults: Data | null /** - * used for getting the keys of a component's raw props + * used for getting the keys of a component's raw props, vapor only * @internal */ - getKeysFromRawProps: () => string[] | undefined + rawKeys?: () => string[] // exposed properties via expose() exposed: Record | null @@ -736,7 +736,6 @@ export function createComponentInstance( // props default value propsDefaults: null, - getKeysFromRawProps: null!, // to be set immediately // inheritAttrs inheritAttrs: type.inheritAttrs, @@ -784,10 +783,6 @@ export function createComponentInstance( } instance.root = parent ? parent.root : instance instance.emit = emit.bind(null, instance) - instance.getKeysFromRawProps = () => { - const { props } = instance.vnode - if (props) return Object.keys(props) - } // apply custom element special handling if (vnode.ce) { diff --git a/packages/runtime-core/src/helpers/useModel.ts b/packages/runtime-core/src/helpers/useModel.ts index c1812407fe5..e85edc6e9a7 100644 --- a/packages/runtime-core/src/helpers/useModel.ts +++ b/packages/runtime-core/src/helpers/useModel.ts @@ -1,7 +1,10 @@ import { type Ref, customRef, ref } from '@vue/reactivity' import { EMPTY_OBJ, camelize, hasChanged, hyphenate } from '@vue/shared' import type { DefineModelOptions, ModelRef } from '../apiSetupHelpers' -import { getCurrentGenericInstance } from '../component' +import { + type ComponentInternalInstance, + getCurrentGenericInstance, +} from '../component' import { warn } from '../warning' import type { NormalizedProps } from '../componentProps' import { watchSyncEffect } from '../apiWatch' @@ -65,19 +68,38 @@ export function useModel( ) { return } - const rawPropKeys = i.getKeysFromRawProps() - if ( - !( - rawPropKeys && - // check if parent has passed v-model - (rawPropKeys.includes(name) || - rawPropKeys.includes(camelizedName) || - rawPropKeys.includes(hyphenatedName)) && - (rawPropKeys.includes(`onUpdate:${name}`) || - rawPropKeys.includes(`onUpdate:${camelizedName}`) || - rawPropKeys.includes(`onUpdate:${hyphenatedName}`)) - ) - ) { + + let rawPropKeys + let parentPassedModelValue = false + let parentPassedModelUpdater = false + + if (i.rawKeys) { + // vapor instance + rawPropKeys = i.rawKeys() + } else { + const rawProps = (i as ComponentInternalInstance).vnode!.props + rawPropKeys = rawProps && Object.keys(rawProps) + } + + if (rawPropKeys) { + for (const key of rawPropKeys) { + if ( + key === name || + key === camelizedName || + key === hyphenatedName + ) { + parentPassedModelValue = true + } else if ( + key === `onUpdate:${name}` || + key === `onUpdate:${camelizedName}` || + key === `onUpdate:${hyphenatedName}` + ) { + parentPassedModelUpdater = true + } + } + } + + if (!parentPassedModelValue || !parentPassedModelUpdater) { // no v-model, local update localValue = value trigger() diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 48f09130a5c..abe72e79cfe 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -285,7 +285,6 @@ export class VaporComponentInstance implements GenericComponentInstance { props: Record attrs: Record propsDefaults: Record | null - getKeysFromRawProps: () => string[] | undefined slots: StaticSlots @@ -395,7 +394,6 @@ export class VaporComponentInstance implements GenericComponentInstance { } else { this.props = this.attrs = EMPTY_OBJ } - this.getKeysFromRawProps = () => getKeysFromRawProps(this.rawProps) // init slots this.rawSlots = rawSlots || EMPTY_OBJ @@ -413,6 +411,14 @@ export class VaporComponentInstance implements GenericComponentInstance { this.emitsOptions = normalizeEmitsOptions(comp) } } + + /** + * Expose `getKeysFromRawProps` on the instance so it can be used in code + * paths where it's needed, e.g. `useModel` + */ + rawKeys(): string[] { + return getKeysFromRawProps(this.rawProps) + } } export function isVaporComponent(