What’s the best way to “extend” a Vue component, i.e. use one component as the basis for other components?

Doing this could save you from duplicating code, making your components quicker to develop and easier to maintain.

There are a number of APIs and patterns that Vue offers for this, and you’ll need to choose the right one depending both on your goals and personal taste.

In this article, I’ll give you an overview of the different options to help you choose the best and most suitable for your scenario.

Do you really need to extend your component?

Keep in mind that all methods of extending components can add complexity and verbosity to your code, and in some cases, additional performance overhead.

So before you decide to extend a component, it’s a good idea to first check if there are simpler design patterns that can achieve what you want.

The following component design patterns can often be sufficient substitutes for extending a component:

  • Props-driven template logic
  • Slots
  • JavaScript utility functions

Let’s do our due diligence by briefly reviewing these.

Props-driven template logic

The easiest way to make a component multi-use, and thus avoid extending it, is to provide a prop which drives conditional logic in the template.

In the following example, we use a prop type for this purpose.

<template>
  <div class="wrapper">
    <div v-if="type === 'a'">...</div>
    <div v-else-if="type === 'b'">...</div>
    <!--etc etc-->
  </div>
</template>
<script>
export default {
  props: { type: String },
  ...
}
</script>

A parent can then declare this component and use the prop to get the variation required.

<template>
  <MyVersatileComponent type="a" />
  <MyVersatileComponent type="b" />
</template>

Here are two indicators that you’ve either hit the limits of this pattern or are misusing it:

  1. The component composition model makes an app scalable by breaking down the state and logic into atomic parts. If you have too many variations in the one component (a “mega component”) you’ll find it won’t be readable or maintainable.
  2. Props and template logic are intended to make a component dynamic but come at a runtime resource cost. It’s an anti-pattern if you’re using this mechanism to solve a code composition problem at runtime.

Slots

Another way to make a component versatile without extending it is to allow the parent component to set custom content within the child using slots.

<template>
  <div class="wrapper">
    <h3>Common markup</div>
    <slot />
  </div>
</template>
<template>
  <MyVersatileComponent>
    <h4>Inserting into the slot</h4>
  </MyVersatileComponent>
</template>

Renders as:

<div class="wrapper">
  <h3>Common markup</div>
  <h4>Inserting into the slot</h4>
</div>

A potential limitation of this pattern is that the elements in the slot belong to the parent’s context, which may not be a natural way of dividing your logic and state.

Scoped slots can bring more flexibility, and we’ll explore these more in the section on renderless components.

JavaScript utility functions

If you only need to reuse standalone functions across your components, you can simply extract these into JavaScript modules without any need to use an extending pattern.

JavaScript’s module system is a very flexible and robust way of sharing code, so you should lean on it where possible.

export default function () {
  ...
}
import MyUtilityFunction from "./MyUtilityFunction";
export default {
  methods: {
    MyUtilityFunction
  }
}

#vue.js #components #composition api #renderless components #vue

Extending Vue.js Components
2.30 GEEK