Mixins

Mixins

Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.

Basic example

Let's say we have a couple of different components whose job it is to toggle a state boolean, a modal and a tooltip. These tooltips and modals don't have a lot in common except for that functionality: they don't look the same, they're not used the same, but the logic is similar.

//modal
{
  data() {
    return {
      isShowing: false
    }
  },

  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },

  components: { AppChild }
}

//tooltip
{
  data() {
    return {
      isShowing: false
    }
  },

  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },

  components: { AppChild }
}

We could extract the logic here and create a mixin that can be reused:

const toggle = {
  data() {
    return {
      isShowing: false
    }
  },

  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}
const Modal = {
  mixins: [toggle],

  components: { AppChild }
};

const Tooltip = {
  mixins: [toggle],

  components: { AppChild }
};

Avoid mixing everything

Mixins are very sexy and is easy to fall in the trap of extracting everything to a mixin. There are cases where all that we need is just another component.

  • Modal A
<template>
  <div>
    <div @toggleShow="click">Toggle</div>
    <ModalA v-if="isShowing" />
  </div>
</template>
export default {
  data() {
    return {
      isShowing: false
    }
  },

  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },

  components: { ModalA }
}
  • Modal B
<template>
  <div>
    <div @toggleShow="click">Toggle</div>
    <ModalB v-if="isShowing" />
  </div>
</template>
export default {
  data() {
    return {
      isShowing: false
    }
  },

  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },

  components: { ModalB }
}

At first sight it seems that we should create a mixin. But even the template for both are very similar. In this case a parent component fits better.

  • Base Modal
<template>
  <div>
    <div @toggleShow="click">Toggle</div>
    <slot v-if="isShowing" />
  </div>
</template>
export default {
  data() {
    return {
      isShowing: false
    }
  },

  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },
}
  • Modal A
<template>
  <BaseModal>
    <ModalA />
  </BaseModal>
</template>
export default {
  components: { BaseModal, ModalA }
}
  • Modal B
<template>
  <BaseModal>
    <ModalB />
  </BaseModal>
</template>
export default {
  components: { BaseModal, ModalB }
}