React JS递归树

时间:2017-02-09 17:03:06

标签: javascript reactjs tree

我正在尝试使用ReactJS递归渲染树结构。我很快就做了一个香草的例子(下图)。现在我把它移植到React并且我已经看了一段时间并且无法弄清楚如何做到这一点。我把我的React示例包含在vanilla示例下。

Vanilla JS

createTree(data, isSub, lev) {
let level = lev || 0;
let html = (isSub) ? '<div class="filter-body">' : ''; // Wrap with div if true
if (isSub) { level++; }

for (let i = 0, len = data.length; i < len; i++) {
    if (typeof(data[i].nested_values) === 'object') {
        html += '<div class="filter-group level-' + level + '">';
        if (isSub) {
            html += '<div class="filter-heading">' + data[i].value + '</div>';
        } else { // Submenu found, but top level list item.
            html += '<div class="filter-heading">' + data[i].value + '</div>';
        }
        // Submenu found, call function recursively
        html += this.createTree(data[i].nested_values, true, level);
        html += '</div>';
    } else {
        html += '<span>' + data[i].value + '</span>' // No submenu, end of tree
    }

}
html += (isSub) ? '</div>' : '';
return html;

}

ReactJS版本

我正在添加一个数组,然后将其映射到我的render方法中的输出。我正在努力解决的部分是如何注入递归调用..我觉得我非常接近,但是看了很长时间,任何想法?

createTree(data, isSub, lev) {
        let level = lev || 0;
        for (let i in data) {
            if (typeof(data[i].nested_values) === 'object') { // Sub array found, build structure
                this.tmpArrB.push(
                    <div class={"filter-group level-" + (level)}>
                        <div class="filter-heading">{data[i].value}</div>
                        {this.createTree(data[i].nested_values, true, level)} // How to do this properly?
                    </div>
                );
            } else { // No submenu, bottom of tree
                this.tmpArrB.push(
                    <span key={i}>
                        {data[i].value}               
                    </span>);
            }
        }
        this.tmpArr.push(<div className='filter-body open'>{this.tmpArrB}</div>);
    }

更新版本(正常工作)

createSelectionHierarchy(data, isSub, level = 1) {
    let children = [];
    if (isSub) { level++; }
    for (let i = 0, len = data.length; i < len; i++) {
        if (typeof(data[i].nested_values) === 'object') { // Sub array found, build structure
            children.push(
                <FilterItem key={i} data={data[i]} level={level}>
                    {this.createSelectionHierarchy(data[i].nested_values, true, level)}
                </FilterItem>
            );
        } else { // No submenu, bottom of tree
            children.push(
                <span key={i}>
                    {data[i].value}               
                </span>);
        }
    }
    return children;
}

Dummy JSON

{
    "possible_values": [{
        "value": "Fruit",
        "occurrence_count": 5,
        "nested_values": [{
            "value": "Berries",
            "occurrence_count": 3,
            "nested_values": [{
                "value": "Strawberry",
                "occurrence_count": 1
            }, {
                "value": "Blackberry",
                "occurrence_count": 1
            }, {
                "value": "Raspberry",
                "occurrence_count": 1
            }, {
                "value": "Redcurrant",
                "occurrence_count": 1
            }, {
                "value": "Blackcurrant",
                "occurrence_count": 1
            }, {
                "value": "Gooseberry",
                "occurrence_count": 1
            }, {
                "value": "Cranberry",
                "occurrence_count": 1
            }, {
                "value": "Whitecurrant",
                "occurrence_count": 1
            }, {
                "value": "Loganberry",
                "occurrence_count": 1
            }, {
                "value": "Strawberry",
                "occurrence_count": 1
            }]
        }, {
            "value": "Tropical",
            "occurrence_count": 2,
            "nested_values": [{
                "value": "Pineapple",
                "occurrence_count": 1
            }, {
                "value": "Mango",
                "occurrence_count": 1
            }, {
                "value": "Guava",
                "occurrence_count": 1
            }, {
                "value": "Passion Fruit",
                "occurrence_count": 1
            }, {
                "value": "Dragon Fruit",
                "occurrence_count": 1
            }]
        }]
    }, {
        "value": "Vegetable",
        "occurrence_count": 2,
        "nested_values": [{
            "value": "Potato",
            "occurrence_count": 3
        }, {
            "value": "Leek",
            "occurrence_count": 3
        }, {
            "value": "Onion",
            "occurrence_count": 3
        }, {
            "value": "Sprout",
            "occurrence_count": 3
        }, {
            "value": "Carrot",
            "occurrence_count": 3
        }, {
            "value": "Runner Bean",
            "occurrence_count": 3
        }, {
            "value": "Swede",
            "occurrence_count": 3
        }, {
            "value": "Turnip",
            "occurrence_count": 3
        }, {
            "value": "Parsnip",
            "occurrence_count": 3
        }, {
            "value": "Kale",
            "occurrence_count": 3
        }, {
            "value": "Spinach",
            "occurrence_count": 3
        }, {
            "value": "Artichoke",
            "occurrence_count": 3
        }, {
            "value": "Broad Bean",
            "occurrence_count": 3
        }, {
            "value": "French Bean",
            "occurrence_count": 3
        }, {
            "value": "Brocolli",
            "occurrence_count": 3
        }, {
            "value": "Cauliflower",
            "occurrence_count": 3
        }, {
            "value": "White Cabbage",
            "occurrence_count": 3
        }, {
            "value": "Red Cabbage",
            "occurrence_count": 3
        }, {
            "value": "Savoy Cabbage",
            "occurrence_count": 3
        }, {
            "value": "Corn",
            "occurrence_count": 3
        }, {
            "value": "Courgette",
            "occurrence_count": 3
        }, {
            "value": "Mange Tout",
            "occurrence_count": 3
        }, {
            "value": "Sweet Potato",
            "occurrence_count": 3
        }, {
            "value": "Pak Choi",
            "occurrence_count": 3
        }]
    }]
}

1 个答案:

答案 0 :(得分:2)

这与任何其他递归函数没有什么不同。为了使这个工作,函数必须返回一些东西。

这一行

{this.createTree(data[i].nested_values, true, level)} // How to do this properly?

表示将this.createTree的返回值作为子元素传递给元素。由于你的函数没有返回任何东西,这不起作用。

更正示例:

createTree(data, isSub, lev) {
    let level = lev || 0;
    let children = [];
    for (let i in data) {
        if (typeof(data[i].nested_values) === 'object') { // Sub array found, build structure
            children.push(
                <div class={"filter-group level-" + (level)}>
                    <div class="filter-heading">{data[i].value}</div>
                    {this.createTree(data[i].nested_values, true, level)}
                </div>
            );
        } else { // No submenu, bottom of tree
            children.push(
                <span key={i}>
                    {data[i].value}               
                </span>
            );
        }
    }
    return <div className='filter-body open'>{children}</div>;
}

如果data是一个数组,请考虑改为使用Array#map