react+antd Recursive Implementation of Tree Directory Operation
- 2021-09-11 19:34:08
- OfStack
STEP 1 Write in front
As the front-end white, I 1 directly tasted the algorithm and data structure, mumbled and suffered. Use multiple recursions to realize the purpose of tree display of data after data formatting, and share my experience of scratching my head this time ~
2. Data
The data from the background is probably like this
{
"data":[
{
"id":1,
"name":"1 Level node ",
"parentId":0,
"isValid":true,
"canAddChild":true,
"parent":null,
"children":[]
},{
"id":3,
"name":"2 Level node ",
"parentId":1,
"isValid":true,
"canAddChild":true,
"parent":null,
"children":[]
}
],
"status":1
}
3. Data format
parentId of each element in data points to id, which is the parent element, and parentId is the top element of the structure tree, but now it is a flat array that is not easy to deal with, and what we have to do is a tree structure, so we must first format the data and put all the child elements of an element into the children attribute of the element. Then, recursion comes.
createTree = data => {
let treeArr = [];
// Gets the top-level parent element collection
let roots = data.filter(elemt => elemt.parentId === 0);
treeArr.push(...roots);
// Starting with the top-level element, get the child elements of each element and put them into the children Attribute
const getChildren = (resultarr,data) => {
resultarr.forEach((elemt,index) => {
elemt.children = data.filter((item,index) => item.parentId === elemt.id);
// Determine whether the current element has a child element added, and if so, then in the child element this 1 Layer cycle
if(elemt.children.length > 0){
getChildren(elemt.children,data);
}
});
}
getChildren(treeArr,data);
// Last updated 1 Lower data
this.setState({
treeArr
})
4. Component format
Because the UI component uses antd, Tree and TreeNode are used as tree structures. Because the data is already tree-like, and we are uncertain about the depth, we want to output UI controls hierarchically, so recursion comes again.
renderTree = jsonTree => jsonTree.map( value => {
// Traverse the tree array, if it finds that it has children Then put it on first <TreeNode>, To him again children Do the same manipulation until the elements in the children Stop for empty elements, indicating that they are already the deepest ones 1 Layer.
if(value.children){
return(
<TreeNode title={
<span>
{value.name}
<Icon type="plus" onClick={this.showModal.bind(this,2,value.id)} />
<Icon type="edit" onClick={this.showModal.bind(this,1,value.id)} />
<Icon type="delete" onClick={this.showModal.bind(this,0,value.id)} />
</span>
} key={value.id}>
// Right children Recursive for each element in
{this.renderTree(value.children)}
</TreeNode>
)
}
})
At this point, the basic completion of the data format and the format of the UI tree, and finally call it in the tree control, OK ~
5. Crazy output
render(){
return(
<Tree showLine={true}>
{this.renderTree(this.state.treeArr)}
</Tree>
)
}
Run, Bingo ~
tips
Because every item in the directory tree is editable, and the original UI component is not available for configuration, the user-defined element of the tree should be added to the title tree of TreeNode after consulting the document, which can be very strong, the official document is finished, haha.
Supplementary knowledge: tree tree component of antd asynchronous loading data small case
Not long ago, when doing business requirements, I encountered a tree selection problem, and the data of child nodes had to be loaded by clicking to expand. In the official document given by antd, there was also demo about dynamic loading of data, but it was not detailed enough. After my own research, I sorted it out and shared it for everyone to learn from.
view. jsx (pure functional declaration)
// Method of rendering tree
const loop = data => data.map((item) => {
const index = item.regionName.indexOf(modelObj.searchValue);
const beforeStr = item.regionName.substr(0, index);
const afterStr = item.regionName.substr(index + modelObj.searchValue.length);
const title = index > -1 ? (
<span>
{beforeStr}
<span style={{ color: '#f50' }}>{modelObj.searchValue}</span>
{afterStr}
</span>
) : <span>{item.regionName}</span>;
if (item.children && item.children.length > 0) {
return (
<TreeNode key={item.regionCode} parentId={item.parentId} title={getTreeTitle(title, item)}>
{loop(item.children)}
</TreeNode>
);
}
return <TreeNode key={item.regionCode} parentId={item.parentId} title={getTreeTitle(title, item)} isGetDealer={item.isGetDealer} isLeaf={item.isLeaf}/>;
});
//Method of triggering tree structure expansion
const onExpand = (expandedKeys) => {
console.log('onExpand-->', expandedKeys);
dispatch({
type: `${namespace}/onExpand`,
payload: {
expandedKeys,
autoExpandParent: false,
}
});
}
//Method of asynchronously loading child nodes of tree structure
const onLoadData = (treeNode) => {
return new Promise((resolve) => {
resolve();
if(treeNode.props.isGetDealer===1){
let cityIds =treeNode.props.eventKey;
dispatch({
type: `${namespace}/queryDealers`,
payload: {
checkedKeys:cityIds,
}
});
}
})
}
Method triggered when//node is selected
const onCheck = (checkedKeys,e) => {
console.log('checkedKeys',checkedKeys);
if(checkedKeys.length > 0) {
updateModel(checkedKeys,'checkedKeys');
} else {
updateModel([], 'sellers');
updateModel([], 'checkedKeys');
}
}
//dom Rendering
return (
{/* Dealer province and city selection */}
{
modelObj.designatSeller === 1 && <div style={{marginBottom:20}}>
<div className = {styles.treeStyle} style={{ backgroundColor: '#FBFBFB', width: 343, paddingLeft: 8, height: 200, overflow: 'auto' }}>
<Tree
checkable
onExpand={onExpand}
expandedKeys={modelObj.expandedKeys}
checkedKeys={modelObj.checkedKeys}
//checkStrictly={true}
autoExpandParent={modelObj.autoExpandParent}
onCheck={onCheck}
loadData={onLoadData}
>
{loop(modelObj.countryList)}
</Tree>
</div>
</div>
}
)
mod.js
// Initial default state
const defaultState = {
countryList:[], // Provincial and municipal trees
expandedKeys: [], // Tree data
autoExpandParent: true,
checkedKeys:[],// Currently selected node
}
//Method list
createTree = data => {
let treeArr = [];
// Gets the top-level parent element collection
let roots = data.filter(elemt => elemt.parentId === 0);
treeArr.push(...roots);
// Starting with the top-level element, get the child elements of each element and put them into the children Attribute
const getChildren = (resultarr,data) => {
resultarr.forEach((elemt,index) => {
elemt.children = data.filter((item,index) => item.parentId === elemt.id);
// Determine whether the current element has a child element added, and if so, then in the child element this 1 Layer cycle
if(elemt.children.length > 0){
getChildren(elemt.children,data);
}
});
}
getChildren(treeArr,data);
// Last updated 1 Lower data
this.setState({
treeArr
})
0
//Get the provincial and municipal tree
createTree = data => {
let treeArr = [];
// Gets the top-level parent element collection
let roots = data.filter(elemt => elemt.parentId === 0);
treeArr.push(...roots);
// Starting with the top-level element, get the child elements of each element and put them into the children Attribute
const getChildren = (resultarr,data) => {
resultarr.forEach((elemt,index) => {
elemt.children = data.filter((item,index) => item.parentId === elemt.id);
// Determine whether the current element has a child element added, and if so, then in the child element this 1 Layer cycle
if(elemt.children.length > 0){
getChildren(elemt.children,data);
}
});
}
getChildren(treeArr,data);
// Last updated 1 Lower data
this.setState({
treeArr
})
1
The data format that the backend needs to return when echoing is as follows:
checkedKeys:[0:"500000,500100,2010093000863693"
1:"500000,500100,2010093000863790"]
This example is only posted 1 part of the important code, specific use of the need to supplement complete.