Skip to content

Commit 1394485

Browse files
authored
refactor(runtime-core): useModel work with vapor mode (#12666)
1 parent 8008509 commit 1394485

File tree

3 files changed

+53
-16
lines changed

3 files changed

+53
-16
lines changed

packages/runtime-core/src/component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ export interface GenericComponentInstance {
366366
* @internal
367367
*/
368368
refs: Data
369+
emit: EmitFn
369370
/**
370371
* used for keeping track of .once event handlers on components
371372
* @internal
@@ -377,6 +378,11 @@ export interface GenericComponentInstance {
377378
* @internal
378379
*/
379380
propsDefaults: Data | null
381+
/**
382+
* used for getting the keys of a component's raw props, vapor only
383+
* @internal
384+
*/
385+
rawKeys?: () => string[]
380386

381387
// exposed properties via expose()
382388
exposed: Record<string, any> | null

packages/runtime-core/src/helpers/useModel.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { type Ref, customRef, ref } from '@vue/reactivity'
22
import { EMPTY_OBJ, camelize, hasChanged, hyphenate } from '@vue/shared'
33
import type { DefineModelOptions, ModelRef } from '../apiSetupHelpers'
4-
import { getCurrentInstance } from '../component'
4+
import {
5+
type ComponentInternalInstance,
6+
getCurrentGenericInstance,
7+
} from '../component'
58
import { warn } from '../warning'
69
import type { NormalizedProps } from '../componentProps'
710
import { watchSyncEffect } from '../apiWatch'
@@ -23,14 +26,14 @@ export function useModel(
2326
name: string,
2427
options: DefineModelOptions = EMPTY_OBJ,
2528
): Ref {
26-
const i = getCurrentInstance()!
29+
const i = getCurrentGenericInstance()!
2730
if (__DEV__ && !i) {
2831
warn(`useModel() called without active instance.`)
2932
return ref() as any
3033
}
3134

3235
const camelizedName = camelize(name)
33-
if (__DEV__ && !(i.propsOptions[0] as NormalizedProps)[camelizedName]) {
36+
if (__DEV__ && !(i.propsOptions![0] as NormalizedProps)[camelizedName]) {
3437
warn(`useModel() called with prop "${name}" which is not declared.`)
3538
return ref() as any
3639
}
@@ -65,19 +68,38 @@ export function useModel(
6568
) {
6669
return
6770
}
68-
const rawProps = i.vnode!.props
69-
if (
70-
!(
71-
rawProps &&
72-
// check if parent has passed v-model
73-
(name in rawProps ||
74-
camelizedName in rawProps ||
75-
hyphenatedName in rawProps) &&
76-
(`onUpdate:${name}` in rawProps ||
77-
`onUpdate:${camelizedName}` in rawProps ||
78-
`onUpdate:${hyphenatedName}` in rawProps)
79-
)
80-
) {
71+
72+
let rawPropKeys
73+
let parentPassedModelValue = false
74+
let parentPassedModelUpdater = false
75+
76+
if (i.rawKeys) {
77+
// vapor instance
78+
rawPropKeys = i.rawKeys()
79+
} else {
80+
const rawProps = (i as ComponentInternalInstance).vnode!.props
81+
rawPropKeys = rawProps && Object.keys(rawProps)
82+
}
83+
84+
if (rawPropKeys) {
85+
for (const key of rawPropKeys) {
86+
if (
87+
key === name ||
88+
key === camelizedName ||
89+
key === hyphenatedName
90+
) {
91+
parentPassedModelValue = true
92+
} else if (
93+
key === `onUpdate:${name}` ||
94+
key === `onUpdate:${camelizedName}` ||
95+
key === `onUpdate:${hyphenatedName}`
96+
) {
97+
parentPassedModelUpdater = true
98+
}
99+
}
100+
}
101+
102+
if (!parentPassedModelValue || !parentPassedModelUpdater) {
81103
// no v-model, local update
82104
localValue = value
83105
trigger()

packages/runtime-vapor/src/component.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
import {
5151
type DynamicPropsSource,
5252
type RawProps,
53+
getKeysFromRawProps,
5354
getPropsProxyHandlers,
5455
hasFallthroughAttrs,
5556
normalizePropsOptions,
@@ -410,6 +411,14 @@ export class VaporComponentInstance implements GenericComponentInstance {
410411
this.emitsOptions = normalizeEmitsOptions(comp)
411412
}
412413
}
414+
415+
/**
416+
* Expose `getKeysFromRawProps` on the instance so it can be used in code
417+
* paths where it's needed, e.g. `useModel`
418+
*/
419+
rawKeys(): string[] {
420+
return getKeysFromRawProps(this.rawProps)
421+
}
413422
}
414423

415424
export function isVaporComponent(

0 commit comments

Comments
 (0)