Vue 2 Internal Features from the Ground Up

Challenge 6: Solution

Evan You

Evan You

Creator of Vue.js
Vue 2 Internal Features from the Ground Up

Check out a free preview of the full Vue 2 Internal Features from the Ground Up course

The "Challenge 6: Solution" Lesson is part of the full, Vue 2 Internal Features from the Ground Up course featured in this preview video. Here's what you'd learn in this lesson:

After discussing functional components prompted by a student question, Evan walks through the solution to Challenge 6.


Transcript from the "Challenge 6: Solution" Lesson

>> Evan You: So let's take a look at how this could be implemented. So foo and bar are pretty straight forward because they simply render static content and since there's no data, no props, we don't need this. We can use the arrow function.
>> Evan You: Wait, no okay, so this is how we do it, right?

So some people in chat has been asking about functional components. And this is in fact a pretty good candidate for functional components because this is the purest form. It doesn't really depend on anything. So turning it into a functional component really is just simple as adding that. And you have a functional component, but this doesn't really help much because this doesn't really depend on any state or props.

So we'll actually go back into 3.1, and take a look at this one. Our example component takes tags, and we're referencing the props via this.tags. The difference between a normal component and or stateful component and functional component is that normal components have an instance, but functional components do not have a backing instance at all.

Functional components as the name suggests, you can think of them as just functions. They take arguments in the return virtual. That's it, it doesn't hold any state of its own. And in fact, in Views version of implementation, functional components are expanded eagerly. So if you use a functional component inside a parent component, this functional component's render function will be invoked eagerly inside that parent component's render function.

So it's kind of expended in line which makes it extremely cheap because there's no overhead of creating a backing instance, holding all these data properties in place and everything. So the perfect use case for functional components is for performance optimizations when you have a lot of leaf nodes.

By leaf nodes, I mean for example you have a huge list, so it's probably inevitable that you have to make each item in the list a real stateful component, but inside each of these components you might have even more components. And those components can be purely presentational. For example, you're just rendering a button, or just rendering a static avatar or something, right?

These components don't really have too much responsibilities in terms of state. Some of them are used to encapsulate some styling, some of them are just like markup, right? If you have these presentational components which simply takes some data, takes some props in and renders some output depending on their props then this seems a perfect candidate for functional components.

And if these components are repeated in many places in your app, turning them into functional ones should boost the performance of an app. So let's take a look at functional components. All we need to do is really just add the functional true option, and it takes the same props declarations as normal components, the difference being that

>> Evan You: Instead of accessing this prompt using this because we no longer have access to this anymore, this is passed in via a second context object, second argument. This is a functional rendering context. So this context object contains a few things. So first, you can access context.props. So props will be held in this context.

You can also have contact.slots. It's a function. When you call this, it's a function. It'll give you resolved slot usage because functional components may also be used with slots. Even if the example is functional, you may be passing things here, right? So how do we access these? So they're passed in via slots, so you can use the same name slots or our name slots API.

This will give you the same as this.slots as a normal render functions and you can also have context.children. So this is different from slots in the sense that this is the raw children. So anything, even if they have slot names on them, you'll just get the raw list of virtual nodes that's passing into this.

So this is only used when you have really low level concerns like you want to do crazy things, but we're not gonna talk too much about it here. And then you can access the context.parent which is the context in which this functional component was rendered in. In this case, the root instance.

Remember, if you do something like this.
>> Evan You: If you're passing example a functional component into another component via slots, usually if example is a stateful component, it's entire parent will be referencing foo here. However in the sense of functional components, the context pairings will be actually referenced in the root instance here.

It only references the context that this function was expanded in instead of the stateful parent. This is because as we said functional components are evaluated eagerly. So this is actually expanded before they're even passed to foo. So when we are here, the instance for foo isn't even created yet, so there's no way to reference it.

>> Evan You: Okay, so we got through that.
>> Evan You: And in here, so we see that it's cool that you can access props here. So this will become, and this completes our functional transformation. But we can simplify this a bit further in that we can use the structuring here, so props { tags }.

So you can destruct multiple props here, like this, foo, bar. And some will find that it's annoying that you have to also explicitly declare props for functional components, and in the latest version of Vue, it's actually optional now. So you can create functional components that don't declare any props.

It'll just bucket collect all the things as props. And yeah, so this is a more concise version. And if you use JSX, we have official Babble plugging called Babble Plugging, transform view JSX that allows you to write JSX, which allows you to do something like this. [SOUND] it’s complaining, but it doesn’t like JSX though.

It can do something like this if you enable JSX in your app. And the cool thing about using JSX is you can actually declare your components this way. So usually when you declare a functional component, you declare it like this, const example like this. You still need this outer object boilerplate declare a function true.

So someone in the Regis team made a bevel transform called bevel plug in transform view functional component or something which allows you to just write it like this, = Props and,
>> Evan You: Yeah, so essentially,
>> Evan You: You can treat them as just a one liner function and to make it look a bit better.

So this is really just a function, and we'll recognize that this function is returning JSX. And we'll compile them into the full version here, and then compile all the JSX into h render calls for you. So if you enable that plugin, this is the most concise form of functional components you can write.

And it's very similar to React functional components as well. So I believe we've talked enough about functional components, and we're gonna look at this. Finally getting to our exercise. So this is gonna be bar
>> Evan You: And we want to implement this example also using render functions, right? So this example takes a prop,

>> Evan You: Okay, and in fact we can make it functional and be done with it. Remember that we can directly return another component as our own root node inside one component. So in this case, what to return depends on this OK prop. So if ok, we'll return foo and if not, we'll return bar.

And this is pretty much it, all right? And in order to complete the test, to pass the test we need to implement a button.
>> Evan You: And yeah, this should put us through the test. Let me try that. Okay,
>> Evan You: Expected to match, it's in reverse, I guess?
>> Speaker 2: You have to initialize ok to true.

>> Evan You: Yeah, I think you got ok in your model. Here, it didn't have this here.
>> Evan You: And right, okay, it doesn't exist in the root scope, so we need to declare that.
>> Evan You: And it passed, great. So yeah, so essentially this is again very concise, toggling between two components and the fact that you can return other component as your own root node.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now