You are on page 1of 6

19/4/2020 Functional Components - Advanced Components | Vue Mastery

Functional Components
In the previous lesson we learned how to create render functions. With this new super power there are
two patterns you can use. The first, which we’ll dive into this lesson, is a functional component which
allows you to:

Create fast-loading presentational components


Create wrapper components

You could think of it like a Component on a diet. Perhaps we want a custom header just for
presentational logic and we decide to write it using a render function:

<div id="app">
<big-topic>
Hiking Boots
</big-topic>
</div>

<script src="vue.js"></script>
<script>
Vue.component('big-topic', {
render(h) {
return h('h1', 'Topic: ' + this.$slots.default)
}
})

new Vue({
el: '#app'
})
</script>

Notice how we’re accessing the default slot, using this.$slots.default .

Using a normal Component for this presentational Component is a little overkill. This is where
functional components start to shine:

https://www.vuemastery.com/courses/advanced-components/functional-components 1/6
19/4/2020 Functional Components - Advanced Components | Vue Mastery

A Functional Component:
Can’t have its own data, computed properties, watchers, lifecycle events, or methods.
Can’t have a template, unless that template is precompiled from a single-file component.
That’s why we used a render function above.
Can be passed things, like props, attributes, events, and slots.
Returns a VNode or an array of VNodes from a render function. Unlike a normal component
that has to have a single root VNode, it can return an array of VNodes.

As you might imagine (without less functionality) a functional component is a little faster. We can make
a functional component by simply adding the option:

Vue.component('big-topic', {
functional: true, // <-----
render(h, context) { // Notice the new context parameter
return h('h1', context.slots().default)
}
})

Notice how we now use the context parameter to access slots? This context argument is how
we get access to to things like props, children, data, parent, listeners, and slots inside a functional
component since we no longer can use this . The official Vue documentation goes into more detail.

If we’re using Vue’s single file components we can declare a functional components at the template
level. Here is the above example as a single file component:

<template functional>
<h1>
<slot></slot>
</h1>
</template>

Yes, that could be the ONLY content in your .vue file. No export default, no props, no data, no
methods, and it will just render out the template. This is great for presentational templates.

Functional Wrapper Components

https://www.vuemastery.com/courses/advanced-components/functional-components 2/6
19/4/2020 Functional Components - Advanced Components | Vue Mastery

Functional components are great to use when you need a way of programmatically delegating to a
specific component. The Vue.js documentation has a great example I’d like to walk you through,
simplified first.

Let’s say you want to create a SmartTable component. If the list passed in is Empty render using
one component, but if it’s not Empty use another component.

The SmartTable component only needs to know how to delegate, it doesn’t have to be very smart,
so it’s going to be a functional component.

<div id="app">
<smart-table :items='vehicles'>
</div>

<script src="vue.js"></script>
<script>
const EmptyTable = {
template: `<h1>Nothing Here</h1>`
}
const NormalTable = { // Normally this would be more complex
template: `<h1>Normal Table</h1>`
}

Vue.component('smart-table', {
functional: true,
props: { items: { type: Array } },
render(h, context) {
if (context.props.items.length > 0 ) { // Delegate
return h(NormalTable, context.data, context.children)
} else {
return h(EmptyTable, context.data, context.children)
https://www.vuemastery.com/courses/advanced-components/functional-components 3/6
19/4/2020 Functional Components - Advanced Components | Vue Mastery

}
}
})
new Vue({
el: '#app',
data: {
vehicles: [ 'Fiat', 'Toyota', 'BMW' ]
}
})
</script>

As you might expect, when the vehicles Array is empty we see the EmptyTable, and when it has one
or more item it displays the Normal Table:

With the h(NormalTable, context.data, context.children) line we’re rendering the


component and passing through all our data which includes attributes, event listeners, and props so
Normal table will have access to them.

Aside: Destructuring Context


When you have a function which receives a JavaScript object as a parameter you can use ES6
destructuring to split it out into variables. It’s not uncommon to see people do this with the context
object like so:

render(h, { props, data, children }) {


if (props.items.length > 0 ) {
return h(NormalTable, data, children)
} else {
return h(EmptyTable, data, children)
}
}

As you can see, the code gets a little simpler.

The More Complex Example

https://www.vuemastery.com/courses/advanced-components/functional-components 4/6
19/4/2020 Functional Components - Advanced Components | Vue Mastery

The example in the Vue documentation is a more complex version of what we have above. Instead of
having just two different components to render our list, we have four in our smart-table. Take a read:

// Here are the four components we're delegating to

var EmptyList = { /* ... */ }


var TableList = { /* ... */ }
var OrderedList = { /* ... */ }
var UnorderedList = { /* ... */ }

Vue.component('smart-list', {
functional: true,
props: {
items: {
type: Array,
required: true
},
isOrdered: Boolean
},
render: function (createElement, context) {

// This function returns which component to use to render


function appropriateListComponent () {
var items = context.props.items

if (items.length === 0) return EmptyList


if (typeof items[0] === 'object') return TableList
if (context.props.isOrdered) return OrderedList

return UnorderedList
}

// Now call the appropriate component.


// Remember that h is short-hand for createElement
return createElement(
appropriateListComponent(),
context.data,
context.children
)
},

})

https://www.vuemastery.com/courses/advanced-components/functional-components 5/6
19/4/2020 Functional Components - Advanced Components | Vue Mastery

As you can see, our functional component just wraps around our other four components.

When you need some sort of wrapper or delegating component, and you care about speed, a
functional component might be the best way to go. In our next lesson, we’ll dive back into the Vue.js
source to figure out more internals of the rendering and mounting process.

https://www.vuemastery.com/courses/advanced-components/functional-components 6/6

You might also like