There are times when you will find yourself rewriting the same code over and over. However, there is a way to prevent this and make yourself far more productive.
For this, you can use what is called a mixin, a special code import in Vue that joins code parts from outside your component to your current component.
Getting ready
The prerequisite for this recipe is Node.js 12+.
The Node.js global objects that are required for his recipe are as follows:
- @vue/cli
- @vue/cli-service-global
To complete this recipe, we will use our Vue project and the Vue CLI, as we did in the Creating a dependency injection component recipe.
How to do it...
Follow these steps to create a component mixin:
- Open the StarRating.vue component.
- In the <script> part, we need to extract the props property into a new file called starRatingDisplay.js that we need to create in the mixins folder. This new file will be our first mixin, and will look like this:
export default {
props: {
maxRating: {
type: Number,
required: false,
default: 5,
},
rating: {
type: Number,
required: false,
default: 0,
},
votes: {
type: Number,
required: false,
default: 0,
},
},
};
- Back in the StarRating.vue component, we need to import this newly created file and add it to a new property called mixin:
<script>
import StarRatingInput from './StarRatingInput.vue';
import StarRatingDisplay from './StarRatingDisplay.vue';
import StarRatingDisplayMixin from '../mixins/starRatingDisplay';
export default {
name: 'StarRating',
components: { StarRatingDisplay, StarRatingInput },
mixins: [StarRatingDisplayMixin],
provide: {
starRating: true,
},
data: () => ({
rank: 0,
voted: false,
}),
computed: {
starComponent() {
if (!this.voted) return StarRatingInput;
return StarRatingDisplay;
},
},
methods: {
vote(rank) {
this.rank = rank;
this.voted = true;
},
},
};
</script>
- Now, we will open the StarRatingDisplay.vue file.
- In the <script> part, we will extract the inject property into a new file called starRatingChild.js, which will be created in the mixins folder. This will be our mixin for the inject property:
export default {
inject: {
starRating: {
default() {
console.error('StarRatingDisplay need to be a child of
StarRating');
},
},
},
};
- Back in the StarRatingDisplay.vue file, in the <script> part, we will extract the methods property into a new file called starRatingName.js, which will be created in the mixins folder. This will be our mixin for the getStarName method:
export default {
methods: {
getStarName(rate) {
if (rate <= this.rating) {
return 'star';
}
if (Math.fround((rate - this.rating)) < 1) {
return 'star_half';
}
return 'star_border';
},
},
};
- Back in the StarRatingDisplay.vue file, we need to import those newly created files and add them to a new property called mixin:
<script>
import StarRatingDisplayMixin from '../mixins/starRatingDisplay';
import StarRatingNameMixin from '../mixins/starRatingName';
import StarRatingChildMixin from '../mixins/starRatingChild';
export default {
name: 'StarRatingDisplay',
mixins: [
StarRatingDisplayMixin,
StarRatingNameMixin,
StarRatingChildMixin,
],
};
</script>
- Open the StarRatingInput.vue file.
- In the <script> part, remove the inject properties and extract the props property into a new file called starRatingBase.js, which will be created in the mixins folder. This will be our mixin for the props property:
export default {
props: {
maxRating: {
type: Number,
required: false,
default: 5,
},
rating: {
type: Number,
required: false,
default: 0,
},
},
};
- Back in the StarRatingInput.vue file, we need to rename the rating data property to rank, and in the getStarName method, we need to add a new constant that will receive either the rating props or the rank data. Finally, we need to import starRatingChildMixin and starRatingBaseMixin:
<script>
import StarRatingBaseMixin from '../mixins/starRatingBase';
import StarRatingChildMixin from '../mixins/starRatingChild';
export default {
name: 'StarRatingInput',
mixins: [
StarRatingBaseMixin,
StarRatingChildMixin,
],
data: () => ({
rank: 0,
}),
methods: {
updateRating(value) {
this.rank = value;
},
emitFinalVote(value) {
this.updateRating(value);
this.$emit('final-vote', this.rank);
},
getStarName(rate) {
const rating = (this.rating || this.rank);
if (rate <= rating) {
return 'star';
}
if (Math.fround((rate - rating)) < 1) {
return 'star_half';
}
return 'star_border';
},
},
};
</script>
How it works...
Mixins merge objects together, but make sure you don't replace an already existing property in your component with an imported one.
The order of the mixins properties is important as well, as they will be checked and imported as a for loop, so the last mixin won't change any properties from any of their ancestors.
Here, we took a lot of repeated parts of our code and split them into four different small JavaScript files that are easier to maintain and improve productivity without us needing to rewrite code.
See also
You can find more information about mixins at https://v3.vuejs.org/guide/mixins.html#mixins.