我正在尝试使用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
}]
}]
}
答案 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
。