Functional Components

Introduction

Our functional Vue 2 Component

src/components/ImageCard.vue
<template functional>
  <div data-name="image-card" class="text-center">
    <div>
      <img :src="props.image" :alt="props.title" class="mx-auto" />
    </div>
    <div>{{ props.title }}</div>
  </div>
</template>

<script>
export default {
  name: 'ImageCard',
  props: {
    image: String,
    title: String,
  },
}
</script>

Migration to a Vue 3 component

  • remove the functional attribute from the template element.
  • Change props, attrs, and emit references to their $-prefixed counterparts

Our component only uses props, but the changes for attrs and emit should be self-explanatory from that.

In Vue 3, there's no longer any separation between `$listeners` and `($)attrs` - the former was merged into the latter. For more info about this, see [Part 3 Chapter XX](#xx)

Vue 3 code:

src/components/ImageCard.vue
<template>
  <div data-name="image-card" class="text-center">
    <div>
      <img :src="$props.image" :alt="$props.title" class="mx-auto" />
    </div>
    <div>{{ $props.title }}</div>
  </div>
</template>

<script>
export default {
  name: 'ImageCard',
  props: {
    image: String,
    title: String,
  },
}
</script>

This is a pretty simple find-and-replace migration, and should work fairly quickly.

Migrating render functions

Your own project might use functional components that were written with render functions. Those could be migrated to normal components as well, following a pattern like the above - the bigger challenge here would be to convert the render function to the new virtualDOM API. You can read more about that in the official Migration guide's chapter on render functions.

Functional components in Vue 3.

there still are functional components in Vue 3, but they are now really "just functions":

import { h } from 'vue'
export function myComponent (props, { attrs, slots, emit }) {
  return h('div', { id: props.id }, slots.default())
}

// optional runtime prop definitions
myComponent.props = {
  id: String
}

As such, they don't support templates anymore, so you have to write the render functions in plain JS or JSX. There usefulness is also limited, as in Vue 3, the performance advantage of functional components over normal, stateful components, is much smaller.

Further reading