loading...

How to replace mixin to slot in Vue.js

terrierscript profile image terrierscript ・2 min read

Mixin is one of Vue.js feature.

https://vuejs.org/v2/guide/mixins.html

This gives options common to multiple components.

React also had a mixin in the past, but it is now deprecated.

This reason is descripted in follow documents.

Summary is here.

  • Introduce implicit dependencies
  • Cause name clashes
  • Cause snowballing complexity

There also may apply on Vue.js.

How to replace mixin? Answer: slot.

In React, we can resolve this probrem with higher order components or functional children.

In Vue.js, we can replace mixin with slot.

In this article, I use mouse event tracking example.

First: Use mixin pattern.

Mixin example is here:

// mouseMixin.js
export default {
  data() {
    return {
      x: 0,
      y: 0
    };
  },
  methods: {
    mousemove(e) {
      this.x = e.clientX;
      this.y = e.clientY;
    }
  }
}

and Components example is here:

<!-- Item -->
<template>
  <div @mousemove="mousemove">
    <div>Item with mixin</div>
    <div>x: {{ x }}</div>
    <div>y: {{ y }}</div>
  </div>
</template>

<script>
import mouseMixin from "./mouseMixin"

export default {
  mixins: [ mouseMixin ],
};
</script>

Finally, components is called those:

<!-- Parent.vue -->
<template>
  <div>
    <Item />
  </div>
</template>

<script>
export default {
  components: {
    Item,
  }
};
</script>

In this example, some properties (x, y and mousemove) is implicit. It's not to easy to find those properties.

Next: Use slot

First, write mixin usage component:

<!-- Item.vue -->
<template>
  <div>
    <div>Item with scope</div>
    <div>x: {{ x }}</div>
    <div>y: {{ y }}</div>
  </div>
</template>

<script>
export default {
  props: {
    x: Number,
    y: Number
  }
};
</script>

This is very simple because got only x and y.

Next, we create MouseEvent component.
This got x and y from mousemove and pass to <slot>

<!-- MouseEvent.vue -->
<template>
  <div @mousemove="mousemove">
    <slot :x="x" :y="y"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      x: 0,
      y: 0
    };
  },
  methods: {
    mousemove(e) {
      this.x = e.clientX;
      this.y = e.clientY;
    }
  }
};
</script>

And last, combine <MouseEvent> and <Item> with slot-scope.

<!-- Parent.vue -->
<template>
  <div>
    <MouseEvent>
      <div slot-scope="{x, y}">
        <Item :x="x" :y="y" />
      </div>
    </MouseEvent>
  </div>
</template>

<script>
export default {
  components: {
    MouseEvent,
    Item,
  },
};
</script>

Okay, It's work.

We can replace slot from mixins. You can use this pattern when avoid mixins
But Vue.js scope is so redundancy. It's a little pain point

Discussion

pic
Editor guide