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.


Related articles: