Skip to content

Commit

Permalink
fix(defineModel): detect changes respect custom getter and setter (#1…
Browse files Browse the repository at this point in the history
…1543)

fix: #11541
fix: #11526
close: #11527
  • Loading branch information
liuseen-l committed Aug 7, 2024
1 parent b1abac0 commit e042888
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 2 deletions.
92 changes: 92 additions & 0 deletions packages/runtime-core/__tests__/helpers/useModel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,4 +657,96 @@ describe('useModel', () => {
expect(setValue).toBeCalledTimes(2)
expect(msg.value).toBe(defaultVal)
})

// #11526
test('custom getter', () => {
let changeChildMsg!: (val: boolean) => void
const getter = (value: boolean) => !value

const Comp = defineComponent({
props: ['msg'],
emits: ['update:msg'],
setup(props) {
const childMsg = useModel(props, 'msg', {
get: getter,
set: value => !value,
})
changeChildMsg = (val: boolean) => (childMsg.value = val)
return () => {
return childMsg.value
}
},
})

const defaultVal = false
const msg = ref(defaultVal)
const Parent = defineComponent({
setup() {
return () =>
h(Comp, {
msg: msg.value,
'onUpdate:msg': val => {
msg.value = val
},
})
},
})

const root = nodeOps.createElement('div')
render(h(Parent), root)

changeChildMsg(!getter(msg.value))
expect(msg.value).toBe(true)

changeChildMsg(!getter(msg.value))
expect(msg.value).toBe(false)
})

// #11541
test('custom setter', () => {
let changeChildMsg!: (val: boolean) => void

const Comp = defineComponent({
props: ['msg'],
emits: ['update:msg'],
setup(props) {
const childMsg = useModel(props, 'msg', {
set: value => {
if (value === msg.value) {
return null
} else {
return value
}
},
})
changeChildMsg = (val: boolean) => (childMsg.value = val)
return () => {
return childMsg.value
}
},
})

const defaultVal = false
const msg = ref(defaultVal)
const Parent = defineComponent({
setup() {
return () =>
h(Comp, {
msg: msg.value,
'onUpdate:msg': val => {
msg.value = val
},
})
},
})

const root = nodeOps.createElement('div')
render(h(Parent), root)

changeChildMsg(true)
expect(msg.value).toBe(true)

changeChildMsg(true)
expect(msg.value).toBe(null)
})
})
5 changes: 3 additions & 2 deletions packages/runtime-core/src/helpers/useModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ export function useModel(
},

set(value) {
const emittedValue = options.set ? options.set(value) : value
if (
!hasChanged(value, localValue) &&
!hasChanged(emittedValue, localValue) &&
!(prevSetValue !== EMPTY_OBJ && hasChanged(value, prevSetValue))
) {
return
Expand All @@ -74,7 +75,7 @@ export function useModel(
localValue = value
trigger()
}
const emittedValue = options.set ? options.set(value) : value

i.emit(`update:${name}`, emittedValue)
// #10279: if the local value is converted via a setter but the value
// emitted to parent was the same, the parent will not trigger any
Expand Down

0 comments on commit e042888

Please sign in to comment.