Polymer 2.0 shifts the inheritance tree of elements from behaviors to mixins. These are decorators applied to the superclass declarations, and work like functions. The Polymer documentation spends a few cycles on the subject matter, but, at least for me, left a whole lot to be desired when it came to explaining how multiple mixins interact, and how I should be using them. To that end, here come some of my observations on using mixins!
Properties
Mixins define properties just like the element would. These properties objects will be fetched from each mixin, so it works just like the “old way”. The fact that the syntax is static get properties() {}
looks initially confusing, but Polymer will iterate over each of the mixins in order to get the full set of properties.
Properties, additionally, seem to behave differently if they are defined compared to when they are not. This is in contrast with Polymer 1, where properties could be used and bound without being defined. I recommend defining any property that the mixin is interested in.
Mixin Order
The mixin order is nested, e.g. A(B(C(baseClass)))
. At least, coming from Polymer 1, it is worth noting that the nesting (i.e. written) order is reversed from Polymer 1. So the above mixin nesting is equivalent to writing behaviors: [C, B, A]
. The outermost mixin gets its functions applied to the final class.
Shorthanding the Mixins
The official documentation proposes the following way to chain mixins:
class AnotherElement extends AnotherMixin(MyMixin(Polymer.Element)) { … }
This becomes unreasonably long after a while. When coding Polymer 1, and porting the code over as it were, I have elements that can easily span 5+ mixins, and the class declaration becomes unbearably long. JavaScript comes to our rescue though — mixins are just functions, so we can easily declare a mixin mixer.
let MyCustomBase = (superclass) => Mixin1(Mixin2(MixinN(superclass)));
This will then allow us to shorthand the mixin calls to a single call.
class MyElement extends MyCustomBase(Polymer.Element)
Mixin Caching
So we have all our mixins and everything is peachy. Well, kind of. One downside of mixins is they are applied again and again to all our class declarations. This isn’t an issue if we only have one custom element, but if we reach tens or even reach a hundred custom elements, we are burning through precious CPU cycles. This counts double on mobile devices.
Luckily, while they don’t advertise it, Polymer has a function called dedupingMixin to cater for this exact use case. This can be used to create a mixin that doesn’t keep applying itself.
TequilaMixin = Polymer.dedupingMixin(base => { let myTempBase = Mixin1(Mixin2(MixinN(base))); // Note that this scope is executed exactly once! Do not try to put hidden variables here. class Tequila extends myTempBase { // Usual class declarations here. constructor(), properties(), etc... } return Tequila; });
Now this TequilaMixin can be used. It will include both the Tequila code but any of the other mixins we include in myTempBase. Thus, not only do we include the shorthand functionality, but this speeds up the class generation time as well. Victory all around!