tree icon indicating copy to clipboard operation
tree copied to clipboard

Possible to use rc-tree in functional react component with react hooks?

Open verwema opened this issue 5 years ago • 4 comments

Hi, is it possible to use rc-tree in functional react component with react hooks? We have rewritten the example for a dynamic tree, but it doesn't display the children correctly.

Is it not advised to rewrite or is there a bug / other issue?

/* eslint-disable no-console, react/no-access-state-in-setstate, react/state-in-constructor */
import React, { useEffect, useState } from 'react';
import Tree from 'rc-tree';
import 'rc-tree/assets/index.css';

function generateTreeNodes(treeNode) {
  const arr = [];
  const key = treeNode.props.eventKey;
  for (let i = 0; i < 3; i += 1) {
    arr.push({ title: `leaf ${key}${i}`, key: `${key}${i}` });
  }
  return arr;
}

function setLeaf(treeData, curKey, level) {
  const loopLeaf = (data, lev) => {
    const l = lev - 1;
    data.forEach(item => {
      if (
        item.key.length > curKey.length
          ? item.key.indexOf(curKey) !== 0
          : curKey.indexOf(item.key) !== 0
      ) {
        return;
      }
      if (item.children) {
        loopLeaf(item.children, l);
      } else if (l < 1) {
        // eslint-disable-next-line no-param-reassign
        item.isLeaf = true;
      }
    });
  };
  loopLeaf(treeData, level + 1);
}

function getNewTreeData(treeData, curKey, child, level) {
  //curkey = 0-1
  // child = [{title: "leaf 0-10", key: "0-10"}]
  //treedata[1] = {title: "pNode 02", key: "0-1"}
  const loop = data => {
    if (level < 1 || curKey.length - 3 > level * 2) return;
    data.forEach(item => {
      if (curKey.indexOf(item.key) === 0) {
        if (item.children) {
          loop(item.children);
        } else {
          // eslint-disable-next-line no-param-reassign
          item.children = child;
        }
      }
    });
  };
  loop(treeData);
  setLeaf(treeData, curKey, level);
}

function Demo(props) {
  //   state = {
  //     treeData: []
  //     //   checkedKeys: []
  //   };

  const [treeData, setTreeData] = useState([]);

  useEffect(() => {
    setTimeout(() => {
      setTreeData([
        { title: 'pNode 01', key: '0-0' },
        { title: 'pNode 02', key: '0-1' },
        { title: 'pNode 03', key: '0-2', isLeaf: true }
      ]);
    }, 100);
  }, []);

  //   componentDidMount() {
  //     setTimeout(() => {
  //       // this.setState(
  //       setTreeData(
  //         [
  //           { title: 'pNode 01', key: '0-0' },
  //           { title: 'pNode 02', key: '0-1' },
  //           { title: 'pNode 03', key: '0-2', isLeaf: true }
  //         ]
  //         //    checkedKeys: ['0-0']
  //       );
  //     }, 100);
  //   }

  //   onSelect = info => {
  //     console.log('selected', info);
  //   };

  //   onCheck = checkedKeys => {
  //     console.log(checkedKeys);
  //     this.setState({
  //       checkedKeys
  //     });
  //   };

  const onLoadData = treeNode => {
    console.log('load data...');
    return new Promise(resolve => {
      setTimeout(() => {
        getNewTreeData(
          treeData,
          treeNode.props.eventKey,
          generateTreeNodes(treeNode),
          2
        );
        setTreeData(treeData);
        resolve();
      }, 2000);
    });
  };

  //render() {
  //    const { treeData } = this.state;

  return (
    <div>
      <h2>dynamic render</h2>
      <Tree
        // onSelect={this.onSelect}
        //   checkable
        // onCheck={this.onCheck}
        //   checkedKeys={this.state.checkedKeys}
        loadData={onLoadData}
        treeData={treeData}
      />
    </div>
  );
}
//}

export default Demo;

verwema avatar Dec 10 '20 10:12 verwema

I have the same issue

image

import '../assets/index.less';
import React, {useState} from 'react'
import Tree from '../src';

function generateTreeNodes(treeNode) {
  const arr = [];
  const key = treeNode.props.eventKey;
  for (let i = 0; i < 3; i += 1) {
    arr.push({ title: `leaf ${key}-${i}`, key: `${key}-${i}` });
  }
  return arr;
}

function getNewTreeData(treeData, curKey, child, level) {
  const loop = data => {
    if (level < 1 || curKey.length - 3 > level * 2) return;
    data.forEach(item => {
      if (curKey.indexOf(item.key) === 0) {
        if (item.children) {
          loop(item.children);
        } else {
          // eslint-disable-next-line no-param-reassign
          item.children = child;
        }
      }
    });
  };
  loop(treeData);
}


export default function DTree(props){

  const [treeData, setTreeData] = useState(()=>{
    return [
      { title: 'pNode 01', key: '0-0' },
      { title: 'pNode 02', key: '0-1' },
      { title: 'pNode 03', key: '0-2', isLeaf: true },
    ]
  })

  const onSelect=(selectedKeys, {selected, selectedNodes, node, event} ) =>{
    console.log('onSelect')
  }

  const onLoadData = (treeNode) => {
    return new Promise(resolve => {
      setTimeout(() => {
        setTreeData( data =>{
          // treeNode.props.isLeaf = false
          getNewTreeData(data, treeNode.props.eventKey, generateTreeNodes(treeNode), 2);
          
          return data
        })
        resolve();
      }, 1000);
    });
  }

  return (<div>
    <h2>dynamic tree</h2>
    <Tree
      onSelect={onSelect}
      // checkable
      // onCheck={this.onCheck}
      // checkedKeys={this.state.checkedKeys}
      loadData={onLoadData}
      treeData={treeData}
    >
    </Tree>
  </div>)
}

laogong5i0 avatar Jan 09 '21 02:01 laogong5i0

Same here, did some one of you found a solution?

snow-dev avatar Feb 16 '21 21:02 snow-dev

Unfortunately not, we kept it in the form of a class for now.

verwema avatar Feb 17 '21 14:02 verwema

If you use the TreeNode component instead of the treeData prop it works sort of. You will have to add the styling you want. So the Tree component would look more like this:

const buildTreeNodes = (nodes: DataNode[]) =>
        nodes.map((data) => (
            <TreeNode key={data.key} title={data.title}>
                {data.children && buildTreeNodes(data.children)}
            </TreeNode>
));

...

<Tree
      onSelect={onSelect}
      loadData={onLoadData}>
    {treeData && buildTreeNodes(treeData)}
</Tree>

I am unsure of if this works with hooks but I did get a lot more functionality using this method rather than the prop so there is a chance it will work better for you.

KalebMatthews avatar Aug 18 '21 16:08 KalebMatthews