Intro to Vue.js

Lessons

1. The Vue Instance

5:42

2. Attribute Binding

2:46

3. Conditional Rendering

3:44

4. List Rendering

2:16

5. Event Handling

4:13

6. Class & Style Binding

5:06

7. Computed Properties

4:57

8. Components

6:20

9. Communicating Events

4:38

10. Forms

9:34

11. Tabs

7:32

Components

Welcome

In this lesson we’ll be learning about the wonderful world of components. Components are reusable blocks of code that can have both structure and functionality. They help create a more modular and maintainable codebase.

Goal

Throughout the course of this lesson we’ll create our first component and then learn how to share data with it.


Starting Code


Problem


In a Vue application, we don’t want all of our data, methods, computed properties, etc. living on the root instance. Over time, that would become unmanageable. Instead, we’ll want to break up our code into modular pieces so that it is easier and more flexible to work with.


Solution

We’ll start out by taking the bulk of our current code and moving it over into a new component for our product.

We register the component like this:

The first argument is the name we choose for the component, and the second is an options object, similar to how we created our initial Vue instance.

In the Vue instance, we used the el property to plug into an element in the DOM. For a component, we use the template property to specify its HTML.

Inside that options object, we’ll add our template.

There are several ways to create a template in Vue, but for now we’ll be using a template literal, with back ticks.

If all of our template code was not nested within one element, such as this div with the class of “product”, we would have gotten this error:

Component template should contain exactly one root element

In other words, a component’s template can only return one element.

So this will work, since it’s only one element:

But this won’t work, since it’s two sibling elements:

So if we have multiple sibling elements, like we have in our product template, they must be wrapped in an outer container element so that the template has exactly one root element:

Now that our template is complete with our product HTML, we’ll add our data, methods and computed properties from the root instance into our new component.

As you can see, this component looks nearly identical in structure to our original instance. But did you notice that data is now a function? Why the change?

Because we often want to reuse components. And if we had multiple product components, we’d need to ensure a separate instance of our data was created for each component. Since data is now a function that returns a data object, each component will definitely have its own data. If data weren’t a function, each product component would be sharing the same data everywhere it was used, defeating the purpose of it being a reusable component.

Now that we’ve moved our product-related code into its own product component, our root instance looks like this:

All we need to do now is neatly tuck our product component within our index.html.

Now our product is being displayed again.

If we open the Vue dev tools, we’ll see that we have the Root and then below that, the Product component.

Just to demonstrate the handy power of components, let’s add two more product components, to see how easy it is to reuse a component.

We’ll only be using one product component moving forward, however.


Problem

Often in an application, a component will need to receive data from its parent. In this case, the parent of our product component is the root instance itself.

Let’s say our root instance has some user data on it, specifying whether the user is a premium account holder. If so, our instance now might look like this:

Let’s also say that if a user is a premium member, then all of their shipping is free.

That means we’ll need our product component to display different values for shipping based on what the value of premium is, on our root instance.

So how can we send premium from the root instance, down into its child, the product component?

Solution

In Vue, we use props to handle this kind of downward data sharing. Props are essentially variables that are waiting to be filled with the data its parent sends down into it.

We’ll start by specifying what props the product component is expecting to receive by adding a props object to our component.

Notice that we’re using some built-in props validation, where we’re specifying the data type of the premium prop as Boolean, and making it required.

Next, in our template, let’s make an element to display our prop to make sure it’s being passed down correctly.

So far so good. Our product component knows that it will be receiving a required boolean, and it also has a place to display that data.

But we have not yet passed premium into the product component. We can do this with a custom attribute, which is essentially a funnel on the component that we can pass premium through.

So what are we doing here?

We’ve given our product component a prop, or a custom attribute, called premium. We are binding that custom attribute : to the premium that lives in our instance’s data.

Now our root instance can pass premium into its child product component. Since the attribute is bound to premium in our root instance’s data, the current value of premium in our instance’s data will always be sent to product.

If we’ve wired this up correctly, we should see: “User is premium: true”.

Great, it’s working. If we check the Vue dev tools, we can see on the right that product now has a prop called premium with the value of true.

Now that we’re successfully passing data into our component, let’s use that data to affect what we show for shipping. Remember, if premium is true, that means shipping is free. So let’s use our premium prop within a computed property called shipping.

Now, we’re using our prop ( this.premium ), and whenever it’s true, shipping will return “Free”. Otherwise, it’ll return 2.99.

Instead of saying User is premium: {{ premium }}, let’s use this element to show our shipping cost, by calling our computed property shipping from here:

And now we see “Shipping: Free”. Why? Because premium is true, so shipping returned “Free”.

Awesome. So now we’ve passed data from our parent into its child component, and used that data within a computed property that displays different shipping values based on the value of our prop.

Great work!

Good to Know: You should not mutate props inside your child components.

What’d we learn

  • Components are blocks of code, grouped together within a custom element
  • Components make applications more manageable by breaking up the whole into resuable parts that have their own structure and behavior
  • Data on a component must be a function
  • Props are used to pass data from parent to child
  • We can specify requirements for the props a component is receiving
  • Props are fed into a component through a custom attribute
  • Props can be dynamically bound to the parent’s data
  • Vue dev tools provide helpful insight about your components

Learn by doing

Challenge:

Create a new component for product-details with a prop of details.