LWCでの再帰的なコンポーネント自分で作る


1.目的

ReactやVueでのコンポネント必要に応じて、時々共通処理のため、再帰的なコンポネントを実装したことがありますが、今回LWCでの再帰的なコンポネントの実装方法を共有します。

2.ソース構成図

lwc
 ├─menu
 ├─menuItem
 └─menuContainer

menu

menu.html
<template>
    <div class="slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open">
        <div class="slds-dropdown slds-dropdown_left slds-dropdown_small">
            <ul class="slds-dropdown__list">
                <c-menu-item child-items={_items}>
                </c-menu-item>
            </ul>
        </div>
    </div>
</template>
menu.js
import { LightningElement, api } from 'lwc';

export default class Menu extends LightningElement {

    @api get items() {
        return this._items || [];
    }

    set items(value) {
        this._items = value;
    }
}
menu.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

menuItem

menuItem.html
<template>
    <template for:each={_children} for:item="it" for:index="index">
        <template if:false={it.items}>
            <li class="slds-dropdown__item" role="presentation" key={item}>
                <a href="#">
                    <span class="slds-truncate" title={it.label}>{it.label}</span>
                </a>
            </li>
        </template>
        <template if:true={it.items}>
            <li class="slds-dropdown__header slds-truncate" key={item}>
                <span title={it.label}>{it.label}</span>
            </li>
            <c-menu-item child-items={it.items} key={item}></c-menu-item>
        </template>
    </template>
</template>
menuItem.js
import { LightningElement, api, track } from 'lwc';

export default class MenuItem extends LightningElement {
    @track _children = [];

    /**
     * childItemsを取得
     */
    @api
    get childItems() {
        return this._children;
    }

    /**
     * childItemsを設定
     * @param {any} value
     */
    set childItems(value) {
        this._children = value || [];
    }
}
menuItem.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

menuContainer

menuContainer.html
<template>
    <div class="slds-card" style="height:500px;width:1200px">
        <c-menu items={items}></c-menu>
    </div>
</template>
menuContainer.js
import { LightningElement, track } from 'lwc';

export default class MenuContainer extends LightningElement {

    @track items = [{
            label: 'メニュー1',
            items: [{
                label: 'サブメニュー1-1',
            }, {
                label: 'サブメニュー1-2',
            }, ],
        },
        {
            label: 'メニュー2',
            items: [{
                label: 'サブメニュー2-1',
            }, {
                label: 'サブメニュー2-2',
            }, ],
        },
    ];
}
menuContainer.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

3.ロカールで動作確認

menuContainer中に右クリックし、SFDX:Preview Component Locallyを押下する

Use Desktop Browserを選択する

サーバを立ち上げて、ブラウザを自動的に開く

4.参考