Components Are Functions

Underneath it all, components are just functions that return some HTML.

It's a huge simplification, and if you've ever looked at the complexity of the Vue codebase you know this isn't actually true. But, fundamentally, this is what Vue is doing for us — plus a million other amazing things.

Take a look at this component:

<template>
<div>
<h1>{{ title }}</h1>
<p>Some words that describe this thing</p>
<button>Clickity click!</button>
</div>
</template>

Now, here is some Javascript that does essentially* the same thing:

function component(title) {
let html = '';
html += '<div>';
html += `<h1>${title}</h1>`;
html += '<p>Some words that describe this thing</p>';
html += '<button>Clickity click!</button>';
html += '</div>';
return html;
}

This code constructs the HTML in much the same way that the Vue component would. Granted, we don't get reactivity, event handling, or a bunch of other features with this, but the HTML that gets output is the same thing.

Code is code

If you've never thought about components in this way, that's normal. Many people don't.

When you start learning Vue you see this new syntax and all these magic words, and it seems so different than anything you've ever touched before.

But if this insight does seem obvious to you, then you've probably had an idea that this was true. Even if you've never seen it laid out like this before, you've probably known this all along.

We can take this insight and extend it to a much stronger and broader claim:

Code is code.

Or, if you prefer:

code === code

Unlike like NaN === NaN, this is always true. So does this statement really say anything, or are we just going in circles?

Leaning on programming fundamentals

Once you truly realize that Vue components are really just functions, it unlocks all of your "hidden" knowledge.

You can take insights that you've picked up from learning Javascript — or any other programming language — and apply them to Vue.

For example, let's say you want to learn how to write really elegant and clean Vue components.

You can take what you've learned about writing clean Javascript and apply them to your Vue components. Things like keeping functions small, using descriptive names, and so on. A good portion of my course, Clean Components, is based on this idea.

Even learning from similar frameworks, like React or Angular, is a really useful exercise.

Of course, there are lots of concepts and techniques that are specific to Vue, which is why I created the course.

Now let's look at a more detailed example.

Refactoring with a new perspective

Previously we've looked at how we can use lonely children to simplify templates when we're using control flow directives, like v-for and v-if.

This parallels exactly to how we would refactor regular Javascript, or any other programming language.

Here is the component that we started with in that article:

<template>
<div>
<h1>{{ title }}</h2>
<div class="navigation">
<!-- ... -->
</div>
<div v-for="item in list">
<h2 class="item-title">
{{ item.title }}
</h2>
<p class="item-description">
{{ item.description }}
</p>
</div>
<footer>
<!-- ... -->
</footer>
</div>
</template>

To simplify we turned what was inside the v-for into a new component that looked like this:

<template>
<div>
<h2 class="item-title">
{{ item.title }}
</h2>
<p class="item-description">
{{ item.description }}
</p>
</div>
</template>

Once we had done that, we replaced it in the parent component, which allowed us to get rid of the extra nesting:

<template>
<div>
<h1>{{ title }}</h2>
<div class="navigation">
<!-- ... -->
</div>
<ListItem
v-for="item in list"
:item="item"
/>
<footer>
<!-- ... -->
</footer>
</div>
</template>

If we were writing Javascript, we would do this in almost exactly the same way.

Here's an example of using a loop:

function goingLoopy() {
const elements = document.querySelectorAll('.item');
for (const el of elements) {
const { width } = el.getBoundingClientRect();
if (width > 500) {
el.classList.add('large');
}
}
}

Here we're grabbing all elements with the class item, and then adding the large class to them if they're wider than 500px.

This is already pretty good, but if you wanted to clean up this code, what would you do?

My guess is that you'd probably take what's inside of the for..of and make that into a new function:

function updateElement(el) {
const { width } = el.getBoundingClientRect();
if (width > 500) {
el.classList.add('large');
}
}
function goingLoopy() {
const elements = document.querySelectorAll('.item');
for (const el of elements) {
updateElement(el);
}
}

This parallels exactly what we were doing in the previous post.

If you think of components as functions, it opens up a whole new world of techniques and methods for you to use.

They've been in your head all this time, you just didn't realize it.

* not really the same thing at all, but this example illustrates my point.