Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Recursive Components in Vue 3

Tech 1

Introduction

In daily Vue projects, component libraries are often used to assist development, so the exposure to recursive components might not be very high. However, this doesn't mean recursive components are unimportant.

This article will help you master the usage of recursive components in about 10 minutes.

Before proceeding, you must have a basic understanding of: html + css + js + Vue3 fundamentals, at least knowing what a Vue component is.

Usage Explanation

Before diving into recursive components, let's clarify a few concepts.

What is Recursion?

Recursion, as defined in Baidu Encyclopedia, is:

The programming technique where a program calls itself is called recursion.

You can roughly think of recursion as a loop, but recursion involves calling itself.

In practice, you need to set a boundary condition for recursion to determine whether to continue recursing.

Without setting a condition, it will lead to infinite recursion, i.e., an endless loop!

What is a Recursive Component?

By now, I believe you know what a Vue component is.

I'll place the Vue3 Recursive Component Documentation here.

Essentially, a recursive component combines "recursion" and "component."

The component calls itself within the boundary condition untill the condition is no longer met.

Where are Recursive Components Used?

In my work, recursive components are used in scenarios such as:

  • Tree components: Used to display file hierarchies.
  • Left navigation bar: Navigation menus generated based on route hierarchies.
  • Multi-level tables (nested tables).

Hands-on Practice

After the previous explanation, you should have a basic concept of recursive components.

Next, we'll explain through a simple example.

The image above is the example we'll implement.

I haven't written any styles, so please use your imagination to visualize this as a website's left navigation bar.

Such navigation bars can be hardcoded on the frontend; or in business scenarios, they might be configured by the backend, with the frontend requesting the navigation data and then generating routes.

Thus, it can be understood that the frontend initially doesn't know how many leveels this navigation has.

This is where recursive components can be utilized.

Steps:

  1. Create a navigation component
  2. Register the navigation component globally
  3. Fetch data (for learning purposes, we'll hardcode the data in the frontend)
  4. Set recursive boundaries in the navigation component and render the data

1. Create the Component

I'll name the navigation component NavigationTree.vue and place it in the components directory.

NavigationTree.vue

<template>
  <div>
    NavigationTree
  </div>
</template>

<script setup>

</script>

<style lang="scss" scoped>

</style>

At this point, the project directory is as follows:

Omitted some directories and files

- src
|- main.js
|- App.vue
|- components
   |- NavigationTree.vue

2. Register the Component Globally

I'll register the NavigationTree.vue component globally, making it convenient for NavigationTree.vue to call itself.

main.js

import { createApp } from 'vue'
import App from './App.vue'
import NavigationTree from './components/NavigationTree.vue' // Import NavigationTree component

const app = createApp(App)

app.component('NavigationTree', NavigationTree) // Register NavigationTree as a global component

app.mount('#app')

Using it in App.vue

App.vue

<template>
  <div>
    <NavigationTree />
  </div>
</template>

The browser interface now looks like the image above.

3. Fetch Navigation Data

In real projects, the left navigation might be fetched from the backend.

But the purpose of this article is to learn recursive components, so we'll directly simulate "requested data" in the frontend.

I'll place the "data fetching" operation in App.vue and then pass it to the NavigationTree.vue component via props.

Mentioning props, I'll briefly note: 10 Ways of Component Communication in Vue3

App.vue

<template>
  <div>
    <NavigationTree :items="navigationData" />
  </div>
</template>

<script setup>
const navigationData = [
  {
    label: 'Level 1 Navigation 1'
  },
  {
    label: 'Level 1 Navigation 2',
    subItems: [
      { label: 'Level 2 Navigation 2-1' },
      {
        label: 'Level 2 Navigation 2-2',
        subItems: [
          { label: 'Level 3 Navigation 2-2-1' },
          { label: 'Level 3 Navigation 2-2-2' },
        ]
      },
      { label: 'Level 2 Navigation 2-3' }
    ]
  },
  {
    label: 'Level 1 Navigation 3'
  }
]
</script>

NavigationTree.vue

<template>
  <div>
    NavigationTree    
  </div>
</template>

<script setup>
const props = defineProps({
  items: {
    type: Array,
    default: () => []
  }
})
</script>

Now, NavigationTree.vue has received the "requested navigation data."

4. Set Recursive Boundaries and Render Data

We see that the navigation data has a subItems field, which means "submenu."

We can determine whether to continue recursing based on the presence of the subItems field. In other words, subItems is the boundary condition for recursion.

NavigationTree.vue

<template>
  <ul>
    <template v-for="node in items" :key="node.label">
      <li>{{ node.label }}</li>
      <NavigationTree v-if="'subItems' in node" :items="node.subItems" />
    </template>
  </ul>
</template>

<script setup>
const props = defineProps({
  items: {
    type: Array,
    default: () => []
  }
})
</script>

The key part is in the HTML code.

This completes the initial goal.

Complete Code

main.js

import { createApp } from 'vue'
import App from './App.vue'
import NavigationTree from './components/NavigationTree.vue'

const app = createApp(App)

app.component('NavigationTree', NavigationTree)

app.mount('#app')

App.vue

<template>
  <div>
    <NavigationTree :items="navigationData" />
  </div>
</template>

<script setup>
const navigationData = [
  {
    label: 'Level 1 Navigation 1'
  },
  {
    label: 'Level 1 Navigation 2',
    subItems: [
      { label: 'Level 2 Navigation 2-1' },
      {
        label: 'Level 2 Navigation 2-2',
        subItems: [
          { label: 'Level 3 Navigation 2-2-1' },
          { label: 'Level 3 Navigation 2-2-2' },
        ]
      },
      { label: 'Level 2 Navigation 2-3' }
    ]
  },
  {
    label: 'Level 1 Navigation 3'
  }
]
</script>

components/NavigationTree.vue

<template>
  <ul>
    <template v-for="node in items" :key="node.label">
      <li>{{ node.label }}</li>
      <NavigationTree v-if="'subItems' in node" :items="node.subItems" />
    </template>
  </ul>
</template>

<script setup>
const props = defineProps({
  items: {
    type: Array,
    default: () => []
  }
})
</script>

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.