[英]Recursively make a nested object given an array of objects and array of children?
[英]How to remove children objects recursively from object?
我正在研究解決方案
每當用戶單擊與單擊的行相關的展開數據時,我已經創建了基本的樹型表,該表將根據行數據出現在其下方
我已經實現了展開/折疊到 N 個嵌套級別的基本功能。
但我只遇到一個問題,所以基本上所有行都有基於具有多個值的數組的條件展開按鈕
假設它是具有 3 個條目的拆分數組,縣、市、state
默認加載的數據將從 api 獲取,現在我必須檢查數組是否有可用的拆分! 如果是的話,我會讓展開按鈕可見
考慮這種情況
const split = ["country","city","state"]
這是 Ui 的樣子
+ Data_1
+ Data_2
單擊按鈕 + 新數據表行將根據下一個可用拆分呈現,在我們的例子中它是國家,所以視覺表示就像
- Data_1
Country_1
Country_2
+ Data_2
這里國家沒有展開按鈕,因為用戶還沒有添加下一個拆分,讓我們添加城市,並假設用戶點擊了 Country_1,所以數據會像
- Data_1
- Country_1
City_1
City_2
+ Country_2
+ Data_2
我的解決方案工作正常,直到這個級別現在可以說用戶已經從拆分中刪除了國家和城市的所有節點,並且 - data_1 的圖標應該更改為 +
這是我的代碼
import React, {useState, useEffect, useRef, Fragment} from "react";
import _ from "lodash";
import axios from "axios";
class TableRowData extends React.Component {
state = {
showIcon: false,
selection: [],
data: [],
splitOption: ["campid"]
};
constructor(props) {
super(props);
}
componentDidMount() {
const checkIfSplitExistOnMount = (currentSplit) => {
const i = _.findIndex(this.state.splitOption, function(el) {
return el === currentSplit;
});
if (this.state.splitOption[i + 1]) {
return this.state.splitOption[i + 1];
} else {
return null;
}
}
const getReportData = () => {
axios.get("https://jsonplaceholder.typicode.com/users?_start=0&_limit=1").then((res) => {
const rowData = res.data.map((row) => {
row.name = this.state.splitOption[0];
row.isExpanded = false;
row.currentSplit = this.state.splitOption[0];
row.nextSplit = checkIfSplitExistOnMount(this.state.splitOption[0])
row.parentId = 0;
row.isVisble = true;
//console.log(row)
return row;
});
this.setState({
data: rowData
}, () => { //console.log(this.state.data)
});
});
}
getReportData()
}
render() {
// update state function
const updateState = () => {
this.setState({
data: [...this.state.data],
splitOption: [...this.state.splitOption],
selection: [...this.state.selection],
}, () => {})
}
// recusively update parent and child
const recursion = (obj) => {
let row = obj;
row.isExpanded = row.isExpanded;
row.currentSplit = row.currentSplit;
row.nextSplit = checkIfSplitExist(row.currentSplit)
if (row.children && row.children.length > 0) { // check if has children
row.children.forEach(v => { // if has children do the same recursion for every children
recursion(v);
});
}
return row; // return final new object
}
const recursionDel = (obj,split) => {
var row = obj;
row.currentSplit = row.currentSplit;
row.nextSplit = checkIfSplitExist(row.currentSplit)
if (row.children && row.children.length > 0) { // check if has children
row.children.forEach(v => { // if has children do the same recursion for every children
recursionDel(v);
});
}
return row; // return final new object
}
// function to check if next split is there or not if there than return nextsplit
const checkIfSplitExist = (currentSplit) => {
const i = _.findIndex(this.state.splitOption, function(el) {
return el === currentSplit;
});
if(i !== -1) {
if (this.state.splitOption[i + 1]) {
return this.state.splitOption[i + 1];
} else {
return null;
}
}
}
// recursive update whenever split added
const recursiveUpdate = (data) => {
const prevData = [...data];
return prevData.map((row) => {
const updatedData = recursion(row);
return row;
});
}
// function to delete child and parent node recursively
const recursiveDelete = (data,split) => {
const prevData = [...data];
return prevData.map((row) => {
const data = recursionDel(row,split);
return row;
});
}
const addNewSplit = (split) => {
const i = _.findIndex(this.state.splitOption, function(el) {
return el === split;
});
if(i === -1) {
this.setState(
{
splitOption:[...this.state.splitOption,split]
},
()=>{
var rowData = recursiveUpdate(this.state.data)
this.setState({data:rowData})
}
);
} else {
const prevData = [...this.state.splitOption];
var index = prevData.indexOf(split);
prevData.splice(index,1)
if(index!==-1) {
this.setState(
{
splitOption:prevData
},
()=> {
var rowData = recursiveDelete(this.state.data,split)
this.setState({data:rowData})
}
)
}
}
}
// add lazyload expand data
const ExpandableTableRow = ({rows}) => {
const expandRow = (row) => {
row.children = [
{
id: "_" + Math.random().toString(36).substr(2, 5),
name: row.id + "_" + row.nextSplit,
isExpanded: false,
parentId: row.id,
currentSplit: row.nextSplit,
nextSplit: checkIfSplitExist(row.nextSplit),
isVisble:true
}, {
id: "_" + Math.random().toString(36).substr(2, 5),
name: row.id + "_" + row.nextSplit,
isExpanded: false,
parentId: row.id,
currentSplit: row.nextSplit,
nextSplit: checkIfSplitExist(row.nextSplit),
isVisble:true
}
];
row.isExpanded = true;
updateState();
};
// call whenever - click
const collapseRow = (row) => {
delete row.children;
row.isExpanded = false;
updateState();
};
// toggle
const ExpandCollapsToggle = ({row, expandRow, collapseRow}) => {
// display +/- only if nextsplit is not undefined or null
if (row.nextSplit) {
if (row.isExpanded === true) {
return (<button type="button" onClick={() => collapseRow(row)}>
-
</button>);
} else {
return (<button type="button" onClick={() => expandRow(row)}>
+
</button>);
}
} else {
return null;
}
};
if (rows) {
return rows.map((row) => {
// if(!_.isEmpty(row)) {
return (<Fragment key={row.id}>
<tr key={row.id}>
<td>
<ExpandCollapsToggle row={row} expandRow={expandRow} collapseRow={collapseRow}/>{" "}
{row.split}
- {row.id}
</td>
<td>{row.name}</td>
</tr>
<ExpandableTableRow rows={row.children}/>
</Fragment>);
// }
});
} else {
return null;
}
};
const splitData = this.state.splitOption.map((ob) => {
return (<Fragment key={ob}><span>{ob}</span> > </Fragment>)
})
if (this.state.data) {
return (
<Fragment>
{splitData} <br/>
<button onClick = {()=>addNewSplit("name")}>camp name</button>
<button onClick = {()=>addNewSplit("os")}>os</button>
<button onClick = {()=>addNewSplit("country")}>country</button>
<ExpandableTableRow rows={this.state.data} />
</Fragment>
);
} else {
return null;
}
}
}
export default TableRowData;
我還創建了代碼框的示例。io -鏈接
這是您如何使用 ui 來復制場景
import React, { useState, useEffect, useRef, Fragment } from "react";
import axios from "axios";
const test_data = [{
"id":1,
"name":"Leanne Graham",
"username":"Bret",
"email":"Sincere@april.biz",
"address":{
"street":"Kulas Light",
"suite":"Apt. 556",
"city":"Gwenborough",
"zipcode":"92998-3874",
"geo":{
"lat":"-37.3159",
"lng":"81.1496"
}
},
"phone":"1-770-736-8031 x56442",
"website":"hildegard.org",
"company":{
"name":"Romaguera-Crona",
"catchPhrase":"Multi-layered client-server neural-net",
"bs":"harness real-time e-markets"
}
}];
class TableRowData extends React.Component {
constructor(props) {
super(props);
this.state = {
showIcon: false,
selection: [],
data: [],
splitOption: ["campid"]
};
}
// function to check if next split is there or not if there than return nextsplit
checkIfSplitExist = (currentSplit) => {
const i = this.state.splitOption.indexOf(currentSplit);
if (i > -1 && this.state.splitOption[i + 1]) {
return this.state.splitOption[i + 1];
}
return null;
}
getReportData = () => {
// axios.get("https://jsonplaceholder.typicode.com/users?_start=0&_limit=1").then(({data}) => {
this.setState({
data: test_data.map((row) => {
row.name = this.state.splitOption[0];
row.isExpanded = false;
row.currentSplit = this.state.splitOption[0];
row.nextSplit = this.checkIfSplitExist(this.state.splitOption[0])
row.parentId = 0;
row.isVisble = true;
console.log(row)
return row;
})
});
// });
}
componentDidMount() {
this.getReportData()
}
render() {
// update state function
const updateState = () => {
this.setState({
data: [...this.state.data],
splitOption: [...this.state.splitOption],
selection: [...this.state.selection],
}, () => { })
}
const recursionUpdateAndDeleteRow = (parentRow, childRow, split, index = 0) => {
childRow.children && childRow.children.forEach((r) => {
recursionUpdateAndDeleteRow(childRow, r, split, index + 1);
});
if (parentRow && split.indexOf(childRow.currentSplit) == -1) {
delete parentRow.children;
}
childRow.currentSplit = split[index];
childRow.nextSplit = split[index + 1] || null;
if (!childRow.children) {
childRow.isExpanded = false;
}
}
const recursionUpdateAndDeleteRows = (rows, split) => {
const _copy = [...rows];
_copy.forEach((row) => {
recursionUpdateAndDeleteRow(null, row, split);
});
return _copy;
}
const toggleSplit = (split) => {
const index = this.state.splitOption.indexOf(split);
let currentSplitOptions = [...this.state.splitOption];
if (index > -1) {
currentSplitOptions.splice(index, 1)
}
else {
currentSplitOptions.push(split);
}
const _data = recursionUpdateAndDeleteRows(this.state.data, currentSplitOptions);
this.setState({
splitOption: currentSplitOptions,
data: _data
})
}
// add lazyload expand data
const ExpandableTableRow = ({ rows }) => {
const expandRow = (row) => {
row.children = [
{
id: "_" + Math.random().toString(36).substr(2, 5),
name: row.id + "_" + row.nextSplit,
isExpanded: false,
parentId: row.id,
currentSplit: row.nextSplit,
nextSplit: this.checkIfSplitExist(row.nextSplit),
isVisble: true
}, {
id: "_" + Math.random().toString(36).substr(2, 5),
name: row.id + "_" + row.nextSplit,
isExpanded: false,
parentId: row.id,
currentSplit: row.nextSplit,
nextSplit: this.checkIfSplitExist(row.nextSplit),
isVisble: true
}
];
row.isExpanded = true;
updateState();
};
// call whenever - click
const collapseRow = (row) => {
delete row.children;
row.isExpanded = false;
updateState();
};
// toggle
const ExpandCollapsToggle = ({ row }) => {
// display +/- only if nextsplit is not undefined or null
if (row.nextSplit) {
if (row.isExpanded) {
return (
<button type="button" onClick={() => collapseRow(row)}>
-
</button>
);
}
return (
<button type="button" onClick={() => expandRow(row)}>
+
</button>
);
}
return null;
};
if (rows) {
return rows.map((row) => {
return (
<Fragment key={row.id}>
<tr key={row.id}>
<td>
<ExpandCollapsToggle
row={row}
/>
{" "}{row.split} - {row.id}
</td>
<td>{row.name}</td>
</tr>
<ExpandableTableRow rows={row.children} />
</Fragment>
);
});
} else {
return null;
}
};
if (this.state.data) {
return (
<Fragment>
{this.state.splitOption.join(', ')} <br />
<button onClick={() => toggleSplit("name")}>
camp name
</button>
<button onClick={() => toggleSplit("os")}>os</button>
<button onClick={() => toggleSplit("country")}>country</button>
<br />
<ExpandableTableRow rows={this.state.data} />
</Fragment>
);
} else {
return null;
}
}
}
export default function App() {
return (
<div>
<TableRowData />
</div>
);
}
這里的工作示例
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.