2017-02-09 96 views
0

我想呈現使用ReactJS遞歸樹形結構。我很快就做了一個香草的例子(下圖)。現在我正在將它移植到React中,並且我一直在考慮它,但無法弄清楚如何去做。我已經將我的React示例包含在了vanilla之下。React JS遞歸樹

香草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版本

我添加到陣列然後映射在其上,以輸出在我的渲染方法。我正在努力圍繞我的頭部的部分是如何注入遞歸調用..我覺得我非常接近,但一直在看它太久了,有什麼想法?

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; 
} 

虛擬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

這取決於你想要的輸出。事實上,您將React元素添加到數組會使事情變得複雜。理想情況下,該函數只是返回一個元素。 –

+1

@FelixKling完全同意你的看法。他也可以利用道具和compo生命週期的概念。 –

+0

這個數組的原因是因爲我想要嵌套可切換的div有更好的方式 - 首先得到這個工作然後重構 – Zinc

回答

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代替。

+0

我只是錯過了回報!? – Zinc

+0

那麼,使用'this.tmpArr'和'this.tmpArrB'也是有問題的。 –

+1

啊,是的,我看你做了什麼!謝謝菲利克斯會在我回家時試試這個 – Zinc