In terms of what has changed, at a high level:
props
and context
(i.e., slots
, attrs
, emit
)functional
attribute on single-file component (SFC) <template>
is removed{ functional: true }
option in components created by functions is removedFor more information, read on!
In Vue 2, functional components had two primary use cases:
However, in Vue 3, the performance of stateful components has improved to the point that the difference is negligible. In addition, stateful components now also include the ability to return multiple root nodes.
As a result, the only remaining use case for functional components is simple components, such as a component to create a dynamic heading. Otherwise, it is recommended to use stateful components as you normally would.
Using the <dynamic-heading>
component, which is responsible for rendering out the appropriate heading (i.e., h1
, h2
, h3
, etc.), this could have been written as a single-file component in 2.x as:
// Vue 2 Functional Component Example export default { functional: true, props: ['level'], render(h, { props, data, children }) { return h(`h${props.level}`, data, children) } }
Or, for those who preferred the <template>
in a single-file component:
<!-- Vue 2 Functional Component Example with <template> --> <template functional> <component :is="`h${props.level}`" v-bind="attrs" v-on="listeners" /> </template> <script> export default { props: ['level'] } </script>
Now in Vue 3, all functional components are created with a plain function. In other words, there is no need to define the { functional: true }
component option.
They will receive two arguments: props
and context
. The context
argument is an object that contains a component's attrs
, slots
, and emit
properties.
In addition, rather than implicitly provide h
in a render
function, h
is now imported globally.
Using the previously mentioned example of a <dynamic-heading>
component, here is how it looks now.
import { h } from 'vue' const DynamicHeading = (props, context) => { return h(`h${props.level}`, context.attrs, context.slots) } DynamicHeading.props = ['level'] export default DynamicHeading
In 3.x, the performance difference between stateful and functional components has been drastically reduced and will be insignificant in most use cases. As a result, the migration path for developers using functional
on SFCs is to remove the attribute and rename all references of props
to $props
and attrs
to $attrs
.
Using our <dynamic-heading>
example from before, here is how it would look now.
<template> <component v-bind:is="`h${$props.level}`" v-bind="$attrs" /> </template> <script> export default { props: ['level'] } </script>
The main differences are that:
functional
attribute removed on <template>
listeners
are now passed as part of $attrs
and can be removedFor more information on the usage of the new functional components and the changes to render functions in general, see:
© 2013–present Yuxi Evan You
Licensed under the MIT License.
https://v3.vuejs.org/guide/migration/functional-components.html