【发布时间】:2021-05-29 12:31:19
【问题描述】:
我正在研究解决方案
每当用户单击展开与单击的行相关的数据时,我已经创建了基本的树型表,该表将根据行数据出现在其下方
我已经实现了展开/折叠最多 N 个嵌套级别的基本功能。
但我只遇到一个问题,所以基本上所有行都有基于具有多个值的数组的条件展开按钮
假设它是具有 3 个条目县、市、州的拆分数组
默认加载的数据将从 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;
我也创建了codesandbox.io的例子-Link
这是你如何使用 ui 来复制场景
- 首先点击阵营名称,会出现展开图标
- 现在如果你想扩展,你可以看到根据拆分的数据
- 现在再添加一个拆分操作系统或国家/地区,您可以看到带有 2 级行的展开图标
- 下一步是删除“阵营名称”,这是删除阵营名称时的问题,应根据可用的拆分重新渲染表格,在我们的例子中,用户的所有行应该被删除,+ 图标必须在那里我们有下一个拆分操作系统或国家/地区可用,我使用默认拆分 ID,它将始终存在
【问题讨论】:
-
请检查答案。
标签: javascript arrays reactjs react-native