Slots Vs Props Vue
Vue comes with two different ways of storing variables, props and data.
28 February 2017 scoped slots example with vue 2.1. Scoped slots example with vue 2.1 In this demo we're using the new scoped slots in Vue 2.1 to create a sortable grid component. The previous chapter was an introduction to the basic concepts of Vue. We will start this chapter with a more realistic approach: we'll introduce Vue-cli. We'll look at the component hierarchy, global and local components, and communication between components. We will introduce slots, and we will also examine the difference between slots and props.
These can be confusing at first, since they seem like they do similar things, and it's not clear when to use one vs the other.
So what's the difference between props and data?
Data
is the private memory of each component where you can store any variables you need. Props are how you pass this data from a parent component down to a child component.
In this article you'll learn:
- What props are, and why this data only flows down, not up
- What the
data
option is used for - What reactivity is
- How to avoid naming collisions between props and
data
- How to use props and data together for fun and profit 💰
What are props?
In Vue, props (or properties), are the way that we pass data from a parent component down to it's child components.
When we build our applications out of components, we end up building a data structure called a tree. Similar to a family tree, you have:
- parents
- children
- ancestors
- and descendants
Data flows down this tree from the root component, the one at the very top. Sort of like how genetics are passed down from one generation to the next, parent components pass props down to their children.
In Vue we add props to components in the <template>
section of our code:
In this example, we are passing the prop cool-prop
a value of 'hello world'
. We will be able to access this value from inside of my-component
.
However, when we access props from inside of a component, we don't own them, so we can't change them (just like you can't change the genes your parents gave you).
Note: While it's possible to change properties in a component, it's a really bad idea. You end up changing the value that the parent is using as well, which can cause lots of confusion.
There is a lot more to props than this. In fact, I wrote a comprehensive guide on using props that teaches all you need to know about props in Vue.
But if we can't change variables, we're kind of stuck.
This is where data
comes in!
What is data?
Data is the memory of each component. This is where you would store data (hence the name), and any other variables you want to track.
If we were building a counter app, we would need to keep track of the count, so we would add a count
to our data
:
This data is private, and only for the component itself to use. Other components do not have access to it.
Note: Again, it is possible for other components to access this data, but for the same reasons, it's a really bad idea to do this!
If you need to pass data to a component, you can use props to pass data down the tree (to child components), or events to pass data up the tree (to parent components).
Props and data are both reactive
With Vue you don't need to think all that much about when the component will update itself and render new changes to the screen.
This is because Vue is reactive.
Instead of calling setState
every time you want to change something, you just change the thing! As long as you're updating a reactive property (props, computed props, and anything in data
), Vue knows to watch for when it changes.
Going back to our counter app, let's take a closer look at our methods:
All we have to do is update count
, and Vue detects this change. It then re-renders our app with the new value!
Vue's reactivity system has a lot more nuance to it, and I believe it's really important to understand it well if you want to be highly productive with Vue. Here are some more things to learn about Vue's reactivity system if you want to dive deeper.
Avoiding naming collisions
There is another great thing that Vue does that makes developing just a little bit nicer.
Slots Vs Props Vue Online
Let's define some props and data on a component:
If we wanted to access them inside of a method, we don't have to do this.props.propA
or this.data.dataA
. Vue let's us omit props
and data
completely, leaving us with cleaner code.
We can access them using this.propA
or this.dataA
:
Because of this, if we accidentally use the same name in both our props
and our data
, we can run into issues.
Vue will give you a warning if this happens, because it doesn't know which one you wanted to access!
The real magic of using Vue happens when you start using props and data
together.
Using props and data together
Now that we've seen how props and data are different, let's see why we need both of them, by building a basic app.
Let's say we are building a social network and we're working on the profile page. We've built out a few things already, but now we have to add the contact info of the user.
We'll display this info using a component called ContactInfo
:
The ContactInfo
component takes the props emailAddress
, twitterHandle
, and instagram
, and displays them on the page.
Our profile page component, ProfilePage
, looks like this:
Our ProfilePage
component currently displays the users profile picture along with their name. It also has the user data object.
How do we get that data from the parent component (ProfilePage
) down into our child component (ContactInfo
)?
We have to pass down this data using props.
First we need to import our ContactInfo
component into the ProfilePage
component:
Second, we have to add in the component to our <template>
section:
Now all the user data that ContactInfo
needs will flow down the component tree and into ContactInfo
from the ProfilePage
!
The reason we keep the data in ProfilePage
and not ContactInfo
is that other parts of the profile page need access to the user object.
Since data only flows down, this means we have to put our data high enough in the component tree so that it can flow down to all of the places it needs to go.
If you enjoyed this article or have any comments, let me know by replying to this tweet!
Composing components with more granular and simpler ones already present in the codebase is a pretty standard situation inside both a web application and, as in my case, a design system repository.
Imagine for example a button component that you can use anywhere, but also a modal component that consumes it as part of its basic interface.
You might already have seen lots of different approaches and techniques for composition in React, like render props or child functions. In this case, I'm going to show you props as component slots or children prop.
And if you have a better name for this please reach out.
# Things to solve
The best way to explain this pattern, and where it shines, is to present the issues and code smells it solved for me.
# Prop 'drilling'
Let's go back to the example I mentioned with a button component available for use and also consumed by a modal and think about its possible prop signature.
The button's content could be the children prop, a kind prop to indicate whether it is a primary or secondary action, an icon prop in case we want an SVG image prepend inside its content and an onClick prop for the click event.
How modal should handle the customization of its button? The immediate thing we do is to match all the props at the component level.
Slots Vs Props Vue App
Of course there's nothing particularly wrong with the code above and you are going to be just fine with this, specially if these two components are unlikely to change with time.
But if they do then maintenance might become a little pain, even more if you use this pattern for button a lot across your codebase.
Slots Vs Props Vue On Tv
It can get even worse if for some reason you have one more component layer between Modal
and Button
.
# Duplicated type definitions
Whether you are using prop types or any language superset to define types, you will have duplicated and unnecessary definitions all over the place, matching exactly the button props definition.
If the signature of the component expands, it will translate into even more work and duplicated definitions, and for something that might be trivial.
# Props as component slots
Slots Vs Props Vue Free
The solution I've found is to pass component through props, this allows you to render a component in a certain section.
Whenever we use Modal
, we just pass an instance of Button
to action.
I haven't experience any inconvenience by doing this. The result is cleaner and more extensible code as we pass the props to Button
directly to the element.
Other stuff you can do is to force certain configuration of the component, for example let's force any button passed to be secondary.
No matter what the developer defines for kind
in the button it will be ignored and 'secondary'
will always be the prop value. This is super useful inside design systems when trying to force certain visual patterns.
# Type checking
One thing that I don't like much about this, and couldn't figure out a better way to do it, is prop type checking of the component is passed.
It's necessary to import the component and check the instance.
Before you say it, no, the following approach doesn't work.
I still think this is a small price to pay, giving all the unnecessary prop manipulation it's saved me, specially inside the design system repository on my current job where internal components are reused as much as possible.
# Wrap up
This technique, props as component slots or however you think this should be called, avoids unnecessary prop handling and repeated type checking.
I haven't detected performance regression around this, but if you do, think about the possibility of switching to another approach that still gives you these benefits while controlling better render cycles.
My recommendation is to hoist the element when possible.
If the action doesn't depend on a higher prop to define its configuration, then turning it into a static element piece will avoid reconciliation around it.
For further reading, I recommend the Composition vs. Inheritance section of the official React docs where this approach receives a short mention at the beginning.