fix(watch): fix watch option merging from mixins

fix #3966
This commit is contained in:
Evan You 2021-06-22 13:54:43 -04:00
parent ab6e927041
commit 9b607fe409
2 changed files with 89 additions and 20 deletions

View File

@ -279,6 +279,67 @@ describe('api: options', () => {
assertCall(spyC, 0, [{ qux: 4 }, { qux: 4 }]) assertCall(spyC, 0, [{ qux: 4 }, { qux: 4 }])
}) })
// #3966
test('watch merging from mixins', async () => {
const mixinA = {
data() {
return {
fromMixinA: ''
}
},
watch: {
obj: {
handler(this: any, to: any) {
this.fromMixinA = to
}
}
}
}
const mixinB = {
data() {
return {
fromMixinB: ''
}
},
watch: {
obj: 'setMixinB'
},
methods: {
setMixinB(this: any, to: any) {
this.fromMixinB = to
}
}
}
let vm: any
const Comp = {
render() {},
mixins: [mixinA, mixinB],
data: () => ({
obj: 'foo',
fromComp: ''
}),
watch: {
obj(this: any, to: any) {
this.fromComp = to
}
},
mounted() {
vm = this
}
}
const root = nodeOps.createElement('div')
render(h(Comp), root)
vm.obj = 'bar'
await nextTick()
expect(vm.fromComp).toBe('bar')
expect(vm.fromMixinA).toBe('bar')
expect(vm.fromMixinB).toBe('bar')
})
test('provide/inject', () => { test('provide/inject', () => {
const symbolKey = Symbol() const symbolKey = Symbol()
const Root = defineComponent({ const Root = defineComponent({

View File

@ -972,25 +972,23 @@ export const internalOptionMergeStrats: Record<string, Function> = {
methods: mergeObjectOptions, methods: mergeObjectOptions,
computed: mergeObjectOptions, computed: mergeObjectOptions,
// lifecycle // lifecycle
beforeCreate: mergeHook, beforeCreate: mergeAsArray,
created: mergeHook, created: mergeAsArray,
beforeMount: mergeHook, beforeMount: mergeAsArray,
mounted: mergeHook, mounted: mergeAsArray,
beforeUpdate: mergeHook, beforeUpdate: mergeAsArray,
updated: mergeHook, updated: mergeAsArray,
beforeDestroy: mergeHook, beforeDestroy: mergeAsArray,
destroyed: mergeHook, destroyed: mergeAsArray,
activated: mergeHook, activated: mergeAsArray,
deactivated: mergeHook, deactivated: mergeAsArray,
errorCaptured: mergeHook, errorCaptured: mergeAsArray,
serverPrefetch: mergeHook, serverPrefetch: mergeAsArray,
// assets // assets
components: mergeObjectOptions, components: mergeObjectOptions,
directives: mergeObjectOptions, directives: mergeObjectOptions,
// watch has special merge behavior in v2, but isn't actually needed in v3. // watch
// since we are only exposing these for compat and nobody should be relying watch: mergeWatchOptions,
// on the watch-specific behavior, just expose the object merge strat.
watch: mergeObjectOptions,
// provide / inject // provide / inject
provide: mergeDataFn, provide: mergeDataFn,
inject: mergeInject inject: mergeInject
@ -1038,13 +1036,23 @@ function normalizeInject(
return raw return raw
} }
function mergeHook( function mergeAsArray<T = Function>(to: T[] | T | undefined, from: T | T[]) {
to: Function[] | Function | undefined,
from: Function | Function[]
) {
return to ? [...new Set([].concat(to as any, from as any))] : from return to ? [...new Set([].concat(to as any, from as any))] : from
} }
function mergeObjectOptions(to: Object | undefined, from: Object | undefined) { function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
return to ? extend(extend(Object.create(null), to), from) : from return to ? extend(extend(Object.create(null), to), from) : from
} }
function mergeWatchOptions(
to: ComponentWatchOptions | undefined,
from: ComponentWatchOptions | undefined
) {
if (!to) return from
if (!from) return to
const merged = extend(Object.create(null), to)
for (const key in from) {
merged[key] = mergeAsArray(to[key], from[key])
}
return merged
}