Mixins
Example:
When a mixin and the component itself contain overlapping options, they will be “merged” using appropriate strategies.
For example, data objects undergo a recursive merge, with the component’s data taking priority in cases of conflicts.
data() {
return {
message: 'hello',
foo: 'abc'
}
}
}
const app = Vue.createApp({
mixins: [myMixin],
data() {
return {
message: 'goodbye',
bar: 'def'
}
},
created() {
console.log(this.$data) // => { message: "goodbye", foo: "abc", bar: "def" }
}
})
Hook functions with the same name are merged into an array so that all of them will be called. Mixin hooks will be called before the component’s own hooks.
const myMixin = {
created() {
console.log('mixin hook called')
}
}
const app = Vue.createApp({
mixins: [myMixin],
created() {
console.log('component hook called')
})
// => "mixin hook called"
// => "component hook called"
You can also apply a mixin globally for a Vue application:
const app = Vue.createApp({
myOption: 'hello!'
})
// inject a handler for `myOption` custom option
app.mixin({
created() {
const myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
app.mount('#mixins-global') // => "hello!"
Use with caution! Once you apply a mixin globally, it will affect every Vue instance created afterwards in the given app (for example, child components):
const app = Vue.createApp({
myOption: 'hello!'
})
// inject a handler for `myOption` custom option
app.mixin({
created() {
const myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
// add myOption also to child component
app.component('test-component', {
})
app.mount('#mixins-global')
// => "hello!"
// => "hello from component!"
In most cases, you should only use it for custom option handling like demonstrated in the example above. It’s also a good idea to ship them as Plugins to avoid duplicate application.
When custom options are merged, they use the default strategy which overwrites the existing value. If you want a custom option to be merged using custom logic, you need to attach a function to app.config.optionMergeStrategies
:
const app = Vue.createApp({
custom: 'hello!'
})
app.config.optionMergeStrategies.custom = (toVal, fromVal) => {
console.log(fromVal, toVal)
// => "goodbye!", undefined
// => "hello", "goodbye!"
return fromVal || toVal
}
app.mixin({
custom: 'goodbye!',
created() {
console.log(this.$options.custom) // => "hello!"
}
})
As you can see, in the console we have toVal
and fromVal
printed first from the mixin and then from the app
. We always return fromVal
if it exists, that’s why this.$options.custom
is set to hello!
in the end. Let’s try to change a strategy to always return a value from the child instance:
const app = Vue.createApp({
custom: 'hello!'
})
app.config.optionMergeStrategies.custom = (toVal, fromVal) => toVal || fromVal
app.mixin({
custom: 'goodbye!',
created() {
console.log(this.$options.custom) // => "goodbye!"
})
In Vue 2, mixins were the primary tool to abstract parts of component logic into reusable chunks. However, they have a few issues:
Reusability is limited: we cannot pass any parameters to the mixin to change its logic which reduces their flexibility in terms of abstracting logic