topic: Vue by Milos Protic relates to: JavaScript, Web Development, Recursive, Component, Recursion on June, 10 2019
Vue and Recursive Components
Quick Introduction
Some people say that recursion is hard to digest. In terms of software development, I don't feel like it is. A simple definition would be that recursive function
is a self-invoking function, meaning that it will invoke itself at a certain point of its execution.
A more theoretical definition would be that recursion
is a behavior requiring two properties:
- A base case - the case which will stop the recursion
- A set of rules responsible for reducing all cases towards the base case
I cannot decide which one is more important. Without the base case, the recursion will become an infinite loop and yet without the reducing cases towards it, we cannot achieve the desired behavior. Anyway, you need both in order to make it function properly.
Recursion and Vue Components
In Vue, recursion is very much possible and quite useful. I mean, not only in Vue, we can follow the rules above to implement recursive behavior in any framework. So, based on the given definition, we can say that a recursive component is a component invoking itself.
When is this useful? Well, whenever you need to use the same template structure, but with hierarchical input data, you can use recursion. Examples are components like tree views for displaying folder structure, comments on your website, nested menus...everything where the parent and the child have the same structure.
Ok, let us build an example to show all of this in practice.
The Problem
Imagine this, you came to work like any other day, made yourself a nice cup of coffee and started reading your favorite blog. Suddenly, your boss comes and says that you need to implement a new page where you will display all folders, subfolders, and files without knowing how many of them will exist. It can show 10, 5 or 100 folders. You start scratching your head thinking about how to solve this, and of course, you think of recursion.
Minimal number of components to solve this is 1, but in our example, we will create two of them:
- The root component
- The folder component
But first, we need to create sample data.
The Data
As mentioned earlier, a recursion comes in handy when we have hierarchically organized data where the child has the same structure as its parent. Here is the data reflecting this:
const root = {
text: 'Root Folder',
leaf: false,
expanded: true,
children: [{
text: 'Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'Sub Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'SomeFile1.js',
leaf: true
}]
}, {
text: 'Sub Sub Folder 2',
leaf: false,
expanded: false,
children: []
}, {
text: 'SomeFile.txt',
leaf: true
}]
}]
}
By having the data above, we are ready to create our components.
The Root Component
This component will be the starting point of our folder tree. It will initiate the rendering of all children, but it can also display some independent information if required since it will not be a part of the recursion itself.
It will contain one property, called folder
for example, to which we will bind our root
data object. This property will be passed on to the child component, which will recursively create the folder tree structure based on it.
Template
<template>
<ul class="folders">
<li>Folders</li>
<folder v-bind:folder="folder"></folder>
</ul>
</template>
The Code
import Folder from './Folder.vue';
export default {
name: 'root',
props: {
folder: Object
},
components: {
Folder
}
};
The Styling
ul.folders {
padding: 1rem;
margin: 0;
box-sizing: border-box;
width: 100%;
list-style: none
}
ul.folders > li:first-child {
padding: 1rem 1rem 1rem 0
}
It's as simple as that.
The Folder component
This component is responsible for rendering each folder in our tree. It will display the information about the current folder and render its children if any. Also, the folders are clickable, and by clicking on one, the component will display its subfolders and files.
Template
<template>
<li class="folder" v-bind:class="[folder.leaf ? 'is-leaf' : 'is-folder']">
<span v-on:click="expand()">{{ folder.text }}</span>
<ul class="sub-folders" v-if="folder.children && folder.children.length > 0" v-show="folder.expanded">
<folder v-for="child in folder.children" v-bind:folder="child"></folder>
</ul>
<div class="folder-empty" v-else v-show="!folder.leaf && folder.expanded">No Data</div>
</li>
</template>
The Code
export default {
name: "folder",
props: {
folder: Object
},
methods: {
expand() {
if (this.folder.leaf) {
return;
}
this.folder.expanded = !this.folder.expanded;
}
}
};
The Styling
li.is-folder {
padding: 1rem;
border-left: 1px solid #d3d3d3;
margin-bottom: 0.5rem
}
li.is-folder > span {
padding: 0.5rem;
border: 1px solid #d3d3d3;
cursor: pointer;
display:inline-block
}
li.is-leaf {
padding: 0 0 0 1rem;
color: #000;
}
ul.sub-folders {
padding: 1rem 1rem 0 0;
margin: 0;
box-sizing: border-box;
width: 100%;
list-style: none
}
div.folder-empty {
padding: 1rem 1rem 0 1rem;
color: #000;
opacity: 0.5
}
Example Usage
In order to use the component you've just created, all you need to do is to import the root
component where this functionality is required and pass in the data structure. For example, on the page your boss requested. The App.vue
component would look something like this:
Template
<template>
<div class="vue-app">
<root v-bind:folder="root"></root>
</div>
</template>
The Code
import Root from './Root.vue';
export default {
name: 'app',
data: function () {
return {
root: {
text: 'Root Folder',
leaf: false,
expanded: true,
children: [{
text: 'Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'Sub Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'SomeFile1.js',
leaf: true
}]
}, {
text: 'Sub Sub Folder 2',
leaf: false,
expanded: false,
children: []
}, {
text: 'SomeFile.txt',
leaf: true
}]
}]
}
}
},
components: {
Root
}
};
And that's it! Your page is ready to display as many folders as it receives.
Wrapping Up
Recursion is not that hard as it looks. It's simple execution of the same code block over and over again with different input parameters until it reaches the base case.
I hope this article will provide a better understanding of recursion and how to create a recursive component with Vue. If this is true, and you find this helpful, show me some love and buy me a coffee to keep me juiced up for more articles.
Thank you for reading!
Subscribe to get the latest posts delivered right to your inbox