再帰は、アルゴリズムで学ぶのが常に苦痛でした。 ただし、場合によっては、再帰を使用する方が反復を使用するよりも自然に感じることがあります。 ツリーをトラバースすることもその1つです。

同じメカニズムに従うことで、Vue.jsやその他のフレームワークで再帰的なコンポーネントを作成できます。

ツリーコンポーネントの作成

たとえば、ディレクトリツリーを表示するなど、ツリー構造をレンダリングする必要があるコンポーネントを想像してみてください。

+ Root directory
  + Directory A
    + Directory A1
  + Directory B

ディレクトリをツリーとして表し、すべてのサブディレクトリをそのツリーのノードのリストとして表すことができます。 ツリーには常にルートノードがあり、リーフノードに到達するまで拡張されます。

たとえば、labelキーとchildrenキーを持つオブジェクトを使用できます。

const tree = {
  label: "A cool folder",
  children: [
    {
      label: "A cool sub-folder 1",
      children: [
        { label: "A cool sub-sub-folder 1" },
        { label: "A cool sub-sub-folder 2" }
      ]
    },
    { label: "This one is not that cool" }
  ]
}

前の構造を前提として、それを小道具として受け取り、ルートノードをレンダリングするTree.vueコンポーネントを作成しましょう。

Tree.vue
<template>
  <div class="tree">
    <ul class="tree-list">
      <node-tree :node="treeData"></node-tree>
    </ul>
  </div>
</template>

<script>
import NodeTree from "./NodeTree";

export default {
  props: {
    treeData: Object
  },
  components: {
    NodeTree
  }
};
</script>

<style>
.tree-list ul {
  padding-left: 16px;
  margin: 6px 0;
}
</style>

リストの左側にいくつかのパディングを追加しているので、リストはその階層的な外観になっています。

ここでは特別なことは何も起こりません。treeDataプロパティを取得し、それを最初のノードとして、まだ実装していないNodeTreeコンポーネントに渡します。

ノードツリーの実装

ノードツリーはそのラベルを表示する必要がありますが、同時にその子をレンダリングする必要があります。 このように、NodeTreeはサブツリーでもあります。

単純なNodeTree.vueコンポーネントは次のようになります。

NodeTree.vue
<template>
  <li class="node-tree">
    <span class="label">{{ node.label }}</span>
  </li>
</template>

<script>
export default {
  props: {
    node: Object
  }
};
</script>

ただし、コンポーネントはラベルを表示するだけであり、ツリーノードでもある子をレンダリングするようにする必要があります。

あなたがそれについて考えるならば、それは再帰関数と同じケースです。 これらは、条件が満たされない限り、自分自身を呼び出す関数です。

したがって、ノードツリーにノードツリーのリストをレンダリングさせる必要があります。 同じコンポーネントからコンポーネントにアクセスするには、nameコンポーネントオプションを追加する必要があります。

NodeTree.vue
<template>
  <li class="node-tree">
    <span class="label">{{ node.label }}</span>

    <ul v-if="node.children && node.children.length">
      <node v-for="child in node.children" :node="child"></node>
    </ul>
  </li>
</template>

<script>
export default {
  name: "node",
  props: {
    node: Object
  }
};
</script>

これにより、 NodeTree コンポーネントは、リーフノードに到達するまでそれ自体を呼び出します。

ご覧のとおり、name: "node"、つまり<node>タグを使用しています。 子ツリーノードは、子が存在する場合にのみレンダリングされ、子ノードをプロパティとして渡します。

ツリーコンポーネントの使用

たとえば、試してみるために、 App.vue コンポーネントを作成して、前のデータ構造をTreeコンポーネントに渡すことができます。

App.vue
<template>
  <div>
    <tree :tree-data="tree"></tree>
  </div>
</template>

<script>
import Tree from "./Tree";

export default {
  data: () => ({
    tree: {
      label: "A cool folder",
      children: [
        {
          label: "A cool sub-folder 1",
          children: [
            { label: "A cool sub-sub-folder 1" },
            { label: "A cool sub-sub-folder 2" }
          ]
        },
        { label: "This one is not that cool" }
      ]
    }
  }),
  components: {
    Tree
  }
};
</script>

まとめ

再帰は難しいものである必要はありません。Vue.jsはDSLまたはテンプレートからのサポートを提供することで簡単に再帰を作成できます。

この記事が素晴らしいツリーコンポーネントの構築に役立つことを願っています!

涼しくしてください🦄