Mixins
Explore how VueJS mixins help you abstract and reuse logic across multiple components. Understand lifecycle hook stacking, custom merge strategies, and using multiple mixins while maintaining manageable code complexity.
We'll cover the following...
This lesson will look at the go-to method for creating reusable code, mixins. Mixins are an excellent way to abstract away similar logic from otherwise different components. Use cases could be form validation, loading user data, or throwing custom events.
What is a mixin?
Mixins are code that we can plug into any component. They’re comparable to the modern-day PHP’s trait feature, which offers the same service. A mixin itself is a component. It provides lifecycle hooks, methods, data, computed fields, and all the things any other component offers. Let’s define a simple mixin as a renderless component:
We can also add mixins to a component, as shown below:
By convention, mixins don’t live in the “src/components” folder but in a separate folder called “src/mixins”. This way, we can always identify components meant to be mixins. Just like renderless components, mixins behave like parent components.
Whatever the mixin defines can be overwritten in the component using the mixin.
The same behavior for inherited hooks also applies to mixins. lifecycle hooks don’t overwrite; they stack. For example, if we have a mounted hook in the mixin and a mounted hook in the component using the mixin, both get executed in the same order as if the component was inheriting from the mixin.
Custom merge strategies
The difference between inherited components and mixins might not be clear. At first glance, inheritance and mixins look very similar. However, there’s a fundamental difference—how options of the mixin and the component are mixed together and the ability to define a mixin globally.
An optionMergeStrategy defines how a mixin is mixed into a component (hence, the name mixin). This strategy is a function that usually takes three arguments—the parent’s value (the component using the mixin), the child’s value (the mixin), and the vm (the Vue instance, if applicable). So, for example, a merge strategy for methods could look like the following:
This merge strategy would not overwrite any methods, but call them all in succession. It’s generally discouraged to use non-standard merge strategies for standard component options. It’s very unclear why a mixin behaves differently from what we would expect. They nevertheless have their use, especially when it comes to custom options.
Let’s create our own merge strategy for the mounted hook. In the following app, there’s a component that uses a mixin. Both implement a mounted hook. Can we overwrite the mounted merge strategy so that only one of the components will be called? If there’s no mounted hook on the component, the merge strategy should use the one on the mixin instead.
<template>
<div></div>
</template>
<script>
import MyMixin from '../mixins/MyMixin.js'
export default {
mixins: [ MyMixin ],
mounted() {
console.log('Mounted Component')
}
}
</script>
This kind of merge strategy can be found in the hint below:
Using multiple mixins
So far, we have only used a single mixin. You might have noticed that the mixins key on a component is plural and has an array as a value. Indeed, a component can use multiple mixins. The order in which they’re mixed in is tied to the order in which they occur in this list.
Since a mixin is also only a component, it can use one or more mixins itself and even inherit from other components. That’s another thing we can try. We prepared another Vue app. Try to rebuild the following structure with mixins and inheritance:
In case of confusion, there’s an explanation of a possible approach in the hint below:
For people not familiar with Unified Modeling Language (UML), each of these classes, except for MyComponent, can be considered a mixin. The diamond at the end of the arrow means has, so, for example, InheritedMixin has MoreMixin. The arrow means inherits, so, for example, SomeMixin extends DeepMixin.
Each of these should have a mounted hook that outputs something, so we can investigate which mixin is applied when.
<script> // TODO: Implement me </script>
Note: While mixins are great to abstract logic away, it’s not recommended to nest them more than two layers deep. Otherwise, the complexity increases and the app becomes less maintainable.