Krzysztof Pintscher
written byKrzysztof Pintscher
posted on September 30, 2022
In Salesforce world since 2014. In the Middle Ages I was an Aura Knight. These days I'm just a LWC cowboy.

Mixins in Lightning Web Components – Dreamforce 2022 session

Introduction

This is a part of session presented on Dreamforce 2022 in Moscone West Developer Theatre. We'll cover only the Mixins part in this post.

You'll learn what the Mixins are, how and when to create your own Mixins for your Lightning Web Components.

Mixins in modern Javascript

There are many different definitions of what mixins actually are - but those definitions are quite similar - if you read them all carefully.
I like to describe Mixins as a abstract subclasses which provides specific behavior and properties for my components (classes).
We can always take a look on [Wikipedia] for more detailed description.
Advantage of usign mixins is fact that you can extend (inherit behavior) from multiple mixins in one component.

Mixins Skeleton for Lightning Web Components

This mixin skeleton is based on Salesforce NavigationMixin code - it's almost like "normal" Javascript mixin, but it has one additional function - assertIsLightningElementSubclass.
As LWC Developer you're familiar with extends LightningElement in every signle component which you saw. So assertIsLightningElementSubclass is actually checking if the object which you're trying to extend with the mixin is actually a LightningElement. Every LightningElement has the dispatchEvent function, right?

This code is your starting point for every single mixin which you'll create. Feel free to use it.

Btw. check the definition of Symbol - you're gonna need it.

function assertIsLightningElementSubclass(Base) {
    const baseProto = Base.prototype;

    if (typeof baseProto.dispatchEvent !== 'function') {
        throw new TypeError(`${Base} must be an Element type`);
    }
}

const BaseMixin = Base => {
    assertIsLightningElementSubclass(Base);
    return class extends Base {};
};

export { BaseMixin };

Real-life example

The base-code or dummy examples are not so exctiting as real-life examples or ideas.
Real-life examples can turn on your imaginations for new ideas, don't you agree?

ModalMixin

Let's assume that you're using modal component provided by Salesforce Devs in recepies. You'll wrap this component multiple times in your code with some other components which will provide content for the slots in this modal component - and also - will controll visibility of this component. That means that you'll repeat yourself many, many times - you'll add functions like:

...
show() {
    this.template.querySelector('c-modal').show();
}
...

It's easier to create and use mixin for that!

import { api } from 'lwc';

const isLightningElementSubclass = Base => {
    const baseProto = Base.prototype;

    if (typeof baseProto.dispatchEvent !== 'function') {
        throw new TypeError(`${Base} must be an Element type`);
    }
};

const GetModal = Symbol('getModal');

const ModalMixin = Base => {
    isLightningElementSubclass(Base);
    return class extends Base {
        @api show() {
            this[GetModal]().show();
        }

        @api hide() {
            this[GetModal]().hide();
        }

        [GetModal]() {
            return this.template.querySelector('c-modal');
        }
    };
};

ModalMixin.GetModal = GetModal;

export { ModalMixin };

So now just imagine that you've got your component with modal inside:

<template>
    <c-modal></c-modal>
</template>

And now your component will extend the ModalMixin and implement a handler to show the modal (but you don't have to implement show function itself, it's already there - inherited from ModalMixin):

import { LightningElement } from 'lwc';
import { ModalMixin } from 'c/modalMixin';

export default class ComponentWithModal extends ModalMixin(LightningElement) {
    ...
    handleModalShow() {
        this.show();
    }
    ...
}

or you can open it from the different component:

import { LightningElement } from 'lwc';

export default class Component extends LightningElement {
    handleOpenModalClick() {
        this.template.querySelector('c-component-with-modal').open();
    }
}

Conclusion

Pretty cool, huh?

I really would like to encourage you to start using this pattern, since it might be a game-changer for your KISS and DRY rules.

All the best,
KP.

Buy Me A Coffee