Skip to content

Commit

Permalink
fix(defineModel): support local mutation when only prop but no listen…
Browse files Browse the repository at this point in the history
…er is passed
  • Loading branch information
yyx990803 committed Dec 30, 2023
1 parent 6fab855 commit 97ce041
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 1 deletion.
35 changes: 35 additions & 0 deletions packages/runtime-core/__tests__/apiSetupHelpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,41 @@ describe('SFC <script setup> helpers', () => {
expect(serializeInner(root)).toBe('bar')
})

test('without parent listener (local mutation)', async () => {
let foo: any
const update = () => {
foo.value = 'bar'
}

const compRender = vi.fn()
const Comp = defineComponent({
props: ['foo'],
emits: ['update:foo'],
setup(props) {
foo = useModel(props, 'foo')
return () => {
compRender()
return foo.value
}
},
})

const root = nodeOps.createElement('div')
// provide initial value
render(h(Comp, { foo: 'initial' }), root)
expect(compRender).toBeCalledTimes(1)
expect(serializeInner(root)).toBe('initial')

expect(foo.value).toBe('initial')
update()
// when parent didn't provide value, local mutation is enabled
expect(foo.value).toBe('bar')

await nextTick()
expect(compRender).toBeCalledTimes(2)
expect(serializeInner(root)).toBe('bar')
})

test('default value', async () => {
let count: any
const inc = () => {
Expand Down
14 changes: 13 additions & 1 deletion packages/runtime-core/src/apiSetupHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
type LooseRequired,
type Prettify,
type UnionToIntersection,
camelize,
extend,
hasChanged,
isArray,
Expand Down Expand Up @@ -380,6 +381,8 @@ export function useModel(
return ref() as any
}

const camelizedName = camelize(name)

const res = customRef((track, trigger) => {
let localValue: any
watchSyncEffect(() => {
Expand All @@ -396,7 +399,16 @@ export function useModel(
},
set(value) {
const rawProps = i.vnode!.props
if (!(rawProps && name in rawProps) && hasChanged(value, localValue)) {
if (
!(
rawProps &&
// check if parent has passed v-model
(name in rawProps || camelizedName in rawProps) &&
(`onUpdate:${name}` in rawProps ||
`onUpdate:${camelizedName}` in rawProps)
) &&
hasChanged(value, localValue)
) {
localValue = value
trigger()
}
Expand Down

0 comments on commit 97ce041

Please sign in to comment.