- A prop to toggle bold/italics. A prop to decide on the max length of the option label before adding an ellipsis. A prop to use as a key to select a value out an object, if the select can be passed an array of objects to list. A prop to apply a prefix or suffix to option labels. And now you have a select with 50 props.
- Slots can be used to change the look and feel of the UI, or to simply swap out text. # footer 3.8.0+ Displayed at the bottom of the component, below.vsdropdown-toggle.
- This is the second part in a five-part series about the JavaScript framework, Vue.js. In this part, we'll go over Components, Props, and Slots.
tldr: If your component does not need to be stateful, turning it into a functional component can increase your rendering performance by 70%.
The child component contains a prop called 'signal'. I would like to be able to change data called 'parentVal' in the parent component so that the children's signal prop is updated with the parent's value. This seems like it should be something simple, but I cannot figure out how to do this using slots: Here is a running example below.
What is a functional component?
Functional components (not to be confused with Vue's render functions) is a component which holds no state and no instance.
In more plain English, this means that the component does not support reactivity and cannot make a reference to itself through the this
keyword.
To create a functional component using Vue's template syntax, you simply add the functional
keyword to the top-level template
tag:
For a component using a render function, you simply set the functional
option to true
:
Accessing component properties
Without the state or instance, you might wonder how you can reference things like data or methods. Fortunately, Vue provides a 'context' parameter (often referred to as ctx
) to the underlying render function.
This 'context' argument is an object with the following properties:
props
: An object of the provided propschildren
: An array of the VNode childrenslots
: A function returning a slots objectscopedSlots
: (v2.6.0+) An object that exposes passed-in scoped slots. Also exposes normal slots as functions.data
: The entire data object, passed to the component as the 2nd argument of createElementparent
: A reference to the parent componentlisteners
: (v2.3.0+) An object containing parent-registered event listeners. This is an alias to data.oninjections
: (v2.3.0+) if using the inject option, this will contain resolved injections.
Accessing this 'context' parameter is pretty straightforward. For example, if we wanted to do something with props, it might look like this:
A quick note on functional components and props:
In a functional component, you actually don't need to register the props that it accepts. However, if you do register them, they will still be validated against their configuration. I personally think it's still a good idea to register them so I can specify the type, required, default value, and/or custom validators.
Why are functional components cool?
Functional components can make accessing your components a little more difficult to work with or introduce some complexity, so why go through the hassle?
Speed.
Because functional components do not have a state, they do not require extra initialization for things like Vue's reactivity system.
Functional components will still react to changes like new props being passed in, but within the component itself, there is no way for it to know when it's data has changed because it does not maintain its own state.
For those of you that prefer hard numbers, I did a benchmark for rendering 1,000 list items as stateful components vs. functional components, and the while the stateful components took on average 140ms, the functional components took about 40ms.
See for yourself: https://codesandbox.io/s/vue-stateful-vs-functional-yterr
For very small applications, you may not notice much of a difference, but for a large application, you should see significant improvements to the DOM render/update events after implementing functional components.
When would you use functional components?
Functional components are probably not right for many cases. After all, the point of using a JavaScript framework is to build applications that are more reactive. In Vue, you cannot do this without the reactivity system in place.
There are, however, some excellent use cases to sprinkle in functional components:
- A component that is simply presentational, AKA a 'dumb' component. For example, buttons, pills, tags, cards, even full pages with just static text like an About page.
- A 'higher order component' which is used to wrap markup or basic functionality around another component.
- Any time you find yourself in a loop (v-for), the items in the loop are usually great candidates.
Functional components are not perfect
They don't inherit attributes as expected
Let's say we have a fancy link component which wraps a bit of style around an HTML tag:
When working with a normal component, any HTML attributes provided from a parent component will be passed directly to a child component. Vue does this for us, and it's a bit of magic how the class
attribute gets resolved:
The output HTML would be (as expected):
This is a perfect opportunity for a functional component, but when we apply the functional
keyword, even if we update all the props as we need to, we do not get the expected output: Casino regina canada.
In order to fix this, we need to provide the attributes to the element we want. This applies to HTML attributes, styles and classes are slightly different, listeners, and refs:
Calling a function within a template is awkward
This is just a small issue I've run into for a pretty specific use case. When using a tag, and accepting data through a prop, sometimes we want to modify the data inside the template.
With a standard Vue component, this is easy using either methods or computed props. With functional components, we do not have access to methods or computed props.
However, there is still a way to do this using $options
.
Let's say our component accepts a 'user'
prop which is an object with 'firstName'
and'lastName'
, and we want to render a template that shows the user's full name.
In a functional component, the way we could do this is by providing a method right on our component definition, then use the
$options
property provided by Vue to access our special method:
I have not personally run into this other issue, but a community member found that try to nest functional components that have scoped slots, the behavior is not the same as nesting stateful components with scoped slots https://github.com/vuejs/vue-loader/issues/1136.
Slots Vs Props Vue On Tv
Why are functional components cool?
Functional components can make accessing your components a little more difficult to work with or introduce some complexity, so why go through the hassle?
Speed.
Because functional components do not have a state, they do not require extra initialization for things like Vue's reactivity system.
Functional components will still react to changes like new props being passed in, but within the component itself, there is no way for it to know when it's data has changed because it does not maintain its own state.
For those of you that prefer hard numbers, I did a benchmark for rendering 1,000 list items as stateful components vs. functional components, and the while the stateful components took on average 140ms, the functional components took about 40ms.
See for yourself: https://codesandbox.io/s/vue-stateful-vs-functional-yterr
For very small applications, you may not notice much of a difference, but for a large application, you should see significant improvements to the DOM render/update events after implementing functional components.
When would you use functional components?
Functional components are probably not right for many cases. After all, the point of using a JavaScript framework is to build applications that are more reactive. In Vue, you cannot do this without the reactivity system in place.
There are, however, some excellent use cases to sprinkle in functional components:
- A component that is simply presentational, AKA a 'dumb' component. For example, buttons, pills, tags, cards, even full pages with just static text like an About page.
- A 'higher order component' which is used to wrap markup or basic functionality around another component.
- Any time you find yourself in a loop (v-for), the items in the loop are usually great candidates.
Functional components are not perfect
They don't inherit attributes as expected
Let's say we have a fancy link component which wraps a bit of style around an HTML tag:
When working with a normal component, any HTML attributes provided from a parent component will be passed directly to a child component. Vue does this for us, and it's a bit of magic how the class
attribute gets resolved:
The output HTML would be (as expected):
This is a perfect opportunity for a functional component, but when we apply the functional
keyword, even if we update all the props as we need to, we do not get the expected output: Casino regina canada.
In order to fix this, we need to provide the attributes to the element we want. This applies to HTML attributes, styles and classes are slightly different, listeners, and refs:
Calling a function within a template is awkward
This is just a small issue I've run into for a pretty specific use case. When using a tag, and accepting data through a prop, sometimes we want to modify the data inside the template.
With a standard Vue component, this is easy using either methods or computed props. With functional components, we do not have access to methods or computed props.
However, there is still a way to do this using $options
.
Let's say our component accepts a 'user'
prop which is an object with 'firstName'
and'lastName'
, and we want to render a template that shows the user's full name.
In a functional component, the way we could do this is by providing a method right on our component definition, then use the
$options
property provided by Vue to access our special method:
I have not personally run into this other issue, but a community member found that try to nest functional components that have scoped slots, the behavior is not the same as nesting stateful components with scoped slots https://github.com/vuejs/vue-loader/issues/1136.
Slots Vs Props Vue On Tv
Another issue I ran into is that functional components cannot have nested component (neither globally or locally registered). This is kind of a big deal, but there is a hacky workaround. The issue was reported in GitHub and the core Vue team admitted it would be a good feature to add, but it's not likely to be implemented since Vue 3.0 should be out soon, making functional components unnecessary.
Conclusion
Slots Vs Props Vue App
If you care about performance or are working on very large applications, consider getting in the practice of creating functional components. The small learning curve is worth the performance gains.
Slots Vs Props Vue Online
References:
https://vuejs.org/v2/guide/render-function.html#Functional-Components
https://itnext.io/whats-the-deal-with-functional-components-in-vue-js-513a31eb72b0