异步加载:

// 父组件 App.js
import logo from './logo.svg';
import './App.css';
import As from "./AsTree.js"
function App() {
  const onCheckTree = (value) => {
    console.log(value, '点击了')
  return (
    <div className="App">
      <As clickTree={onCheckTree} baseApi={"https://xxx.xxx.cn"} token={"L6qbt0KutJyV0L8I_R6Mw7yYueNmSLCFLWx1Duqf3zQ.BdmQm8Kry1mobxOlGCgFt7mQsyRwiVPHO21aLJdM3hk"} />
export default App;
// 子组件 AsTree.js
import {
  } from 'antd';
  import React, {
    useState,
    useEffect
  } from 'react';
  import { DownOutlined } from '@ant-design/icons';
  import './App.css';
  const updateTreeData = (list, key, children) =>
    list.map((node) => {
      if (node.key === key) {
        return {
          ...node,
          children
      if (node.children) {
        return {
          ...node,
          children: updateTreeData(node.children, key, children)
      return node;
  const App = (props) => {
    const [treeData, setTreeData] = useState([]);
    useEffect(() => {
      fetch(`${props.baseApi}/api/efast/v1/entry-doc-lib`, {
        method: "GET",
        headers: {
          'authorization': "Bearer " + props.token
      }).then((response) => response.json()).then(resJson => {
        const typeArr = [];
        const user_doc_lib = [];
        const department_doc_lib = [];
        const custom_doc_lib = [];
        const shared_user_doc_lib = [];
        const knowledge_doc_lib = [];
        for (let i = 0; i < resJson.length; i++) {
          if (typeArr.indexOf(resJson[i].type) < 0) {
            typeArr.push(resJson[i].type);
          if (resJson[i].type === "user_doc_lib") {
            user_doc_lib.push({
              key: resJson[i]["id"],
              title: resJson[i]["name"],
              isLeaf: false
          } else if (resJson[i].type === "department_doc_lib") {
            department_doc_lib.push({
              key: resJson[i]["id"],
              title: resJson[i]["name"],
              isLeaf: false
          } else if (resJson[i].type === "custom_doc_lib") {
            custom_doc_lib.push({
              key: resJson[i]["id"],
              title: resJson[i]["name"],
              isLeaf: false
          } else if (resJson[i].type === "shared_user_doc_lib") {
            shared_user_doc_lib.push({
              key: resJson[i]["id"],
              title: resJson[i]["name"],
              isLeaf: false
          } else if (resJson[i].type === "knowledge_doc_lib") {
            knowledge_doc_lib.push({
              key: resJson[i]["id"],
              title: resJson[i]["name"],
              isLeaf: false
        for (let i = 0; i < typeArr.length; i++) {
          if (typeArr[i] == "user_doc_lib") {
            typeArr[i] = {
              key: 0,
              title: "个人文档库",
              isLeaf: false,
              children: user_doc_lib
          } else if (typeArr[i] == "department_doc_lib") {
            typeArr[i] = {
              key: 1,
              title: "部门文档库",
              isLeaf: false,
              children: department_doc_lib
          } else if (typeArr[i] == "custom_doc_lib") {
            typeArr[i] = {
              key: 2,
              title: "自定义文档库",
              isLeaf: false,
              children: custom_doc_lib
          } else if (typeArr[i] == "shared_user_doc_lib") {
            typeArr[i] = {
              key: 3,
              title: "共享个人文档库",
              isLeaf: false,
              children: shared_user_doc_lib
          } else if (typeArr[i] == "knowledge_doc_lib") {
            typeArr[i] = {
              key: 4,
              title: "知识库",
              isLeaf: false,
              children: knowledge_doc_lib
        setTreeData(typeArr)
      }).catch(err => console.log('Request Failed', err));
    }, [])
    const onLoadData = ({
      children
      new Promise((resolve) => {
        if (children) {
          resolve();
          return;
        fetch(`${props.baseApi}/api/efast/v1/dir/list`, {
          method: "POST",
          headers: {
            'authorization': "Bearer " + props.token
          body: JSON.stringify({
            docid: key
        }).then((response) => response.json()).then(resJson => {
          const options = [];
          for (let i = 0; i < resJson.dirs.length; i++) {
            options.push({
              key: resJson.dirs[i]["docid"],
              title: resJson.dirs[i]["name"],
              isLeaf: false
          for (let i = 0; i < resJson.files.length; i++) {
            options.push({
              key: resJson.files[i]["docid"],
              title: resJson.files[i]["name"],
              isLeaf: true
          setTreeData((origin) =>
            updateTreeData(origin, key, options),
          resolve();
        }).catch(err => console.log('Request Failed', err));
    const onCheck = (checkedKeys, info) => {
      console.log('onCheck', checkedKeys, info);
      props.clickTree(info);
    return <Tree switcherIcon={<DownOutlined />} loadData={
      onLoadData
      treeData={
        treeData
      checkable={
      blockNode selectable={
        false
      onCheck={onCheck}
  export default App;

异步加载TS版:

// App.tsx
import React from 'react';
import './App.css';
import AnyShareTree from "./AnyShareTree"
function App() {
  const onCheckTree = (value: any) => {
    console.log(value, "test")
  return (
    <div className="App">
      <AnyShareTree clickTree={onCheckTree} baseApi={"https://anyshare.aishu.cn"} token={"kx7e88Kd-GtUgdc43V2gd-PfYufsgpbPWK0OP9ieGOs.uymaPkjLUnq3-Cxo8zZ2Fi3WhW_d5U3s1LsMtIs2jvE"} />
export default App;
// AsTree.tsx
import { DownOutlined } from '@ant-design/icons';
import {
    Tree, message
} from 'antd';
// import type { DataNode, TreeProps } from 'antd/es/tree';
import React, {
    useState,
    useEffect
} from 'react';
import './App.css';
const AS_DownOutlined: any = DownOutlined;
interface DataNode {
    title: string;
    key: string;
    isLeaf?: boolean;
    children?: DataNode[];
interface IProps {
    baseApi: string;
    token: string;
    clickTree: (value: any) => any;
const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] =>
    list.map((node) => {
        if (node.key === key) {
            return {
                ...node,
                children
        if (node.children) {
            return {
                ...node,
                children: updateTreeData(node.children, key, children)
        return node;
const App: React.FC<IProps> = (props: IProps) => {
    const [treeData, setTreeData] = useState<DataNode[] | []>([]);
    useEffect(() => {
        fetch(`${props.baseApi}/api/efast/v1/entry-doc-lib`, {
            method: "GET",
            headers: {
                'authorization': "Bearer " + props.token
        }).then((response) => {
            if (response.ok) {
                return response.json()
            } else {
                return Promise.reject({
                    status: response.status,
                    statusText: response.statusText,
                    url: response.url
        }).then(resJson => {
            const typeArr: any = [];
            const user_doc_lib = [];
            const department_doc_lib = [];
            const custom_doc_lib = [];
            const shared_user_doc_lib = [];
            const knowledge_doc_lib = [];
            for (let i = 0; i < resJson.length; i++) {
                if (typeArr.indexOf(resJson[i].type) < 0) {
                    typeArr.push(resJson[i].type);
                if (resJson[i].type === "user_doc_lib") {
                    user_doc_lib.push({
                        key: resJson[i]["id"],
                        title: resJson[i]["name"],
                        isLeaf: false
                } else if (resJson[i].type === "department_doc_lib") {
                    department_doc_lib.push({
                        key: resJson[i]["id"],
                        title: resJson[i]["name"],
                        isLeaf: false
                } else if (resJson[i].type === "custom_doc_lib") {
                    custom_doc_lib.push({
                        key: resJson[i]["id"],
                        title: resJson[i]["name"],
                        isLeaf: false
                } else if (resJson[i].type === "shared_user_doc_lib") {
                    shared_user_doc_lib.push({
                        key: resJson[i]["id"],
                        title: resJson[i]["name"],
                        isLeaf: false
                } else if (resJson[i].type === "knowledge_doc_lib") {
                    knowledge_doc_lib.push({
                        key: resJson[i]["id"],
                        title: resJson[i]["name"],
                        isLeaf: false
            for (let i = 0; i < typeArr.length; i++) {
                if (typeArr[i] === "user_doc_lib") {
                    typeArr[i] = {
                        key: 0,
                        title: "个人文档库",
                        isLeaf: false,
                        children: user_doc_lib
                } else if (typeArr[i] === "department_doc_lib") {
                    typeArr[i] = {
                        key: 1,
                        title: "部门文档库",
                        isLeaf: false,
                        children: department_doc_lib
                } else if (typeArr[i] === "custom_doc_lib") {
                    typeArr[i] = {
                        key: 2,
                        title: "自定义文档库",
                        isLeaf: false,
                        children: custom_doc_lib
                } else if (typeArr[i] === "shared_user_doc_lib") {
                    typeArr[i] = {
                        key: 3,
                        title: "共享个人文档库",
                        isLeaf: false,
                        children: shared_user_doc_lib
                } else if (typeArr[i] === "knowledge_doc_lib") {
                    typeArr[i] = {
                        key: 4,
                        title: "知识库",
                        isLeaf: false,
                        children: knowledge_doc_lib
            setTreeData(typeArr)
        }).catch(err => message.error(JSON.stringify(err)));
    }, [])
    const onLoadData = ({
        children
    }: any) =>
        new Promise<void>((resolve) => {
            if (children) {
                resolve();
                return;
            fetch(`${props.baseApi}/api/efast/v1/dir/list`, {
                method: "POST",
                headers: {
                    'authorization': "Bearer " + props.token
                body: JSON.stringify({
                    docid: key
            }).then((response) => {
                if (response.ok) {
                    return response.json()
                } else {
                    return Promise.reject({
                        status: response.status,
                        statusText: response.statusText,
                        url: response.url
            }).then(resJson => {
                const options: any[] = [];
                for (let i = 0; i < resJson.dirs.length; i++) {
                    options.push({
                        key: resJson.dirs[i]["docid"],
                        title: resJson.dirs[i]["name"],
                        isLeaf: false
                for (let i = 0; i < resJson.files.length; i++) {
                    options.push({
                        key: resJson.files[i]["docid"],
                        title: resJson.files[i]["name"],
                        isLeaf: true
                setTreeData((origin) =>
                    updateTreeData(origin, key, options),
                resolve();
            }).catch(err => message.error(JSON.stringify(err)));
    const onCheck: any = (checkedKeys: any, info: any) => {
        console.log('onCheck', checkedKeys, info);
        props.clickTree(info);
    return <Tree switcherIcon={<AS_DownOutlined />} loadData={onLoadData} treeData={treeData} checkable={true} blockNode selectable={false} onCheck={onCheck} />;
export default App;
import React from 'react';
import {Tree, Input} from 'antd';
const TreeNode = Tree.TreeNode;
const Search = ...
                                    实现Ant Design Tree组件的节点的增删改
在做项目时最近遇到一个需求,需要用到Antdtree,并能够实现对tree的节点的增加和删除,以及节点名称的修改。去翻Antd官网文档,发现tree组件并没有提供关于节点操作的api,但是有鼠标右击的api。借助这个鼠标右击,以及其他组件是可以实现对节点的增删改。下面进行截图介绍:
第一部分:Tree组件
最外层节点只能增加子节点
父节点可以增加子节点,修改自己的节点名称,删除节点
3.最内层节点不允许再添加子节点,只允许修改自己的
最近在用Ant Design写一个后台,遇到的需求就是实现一个可动态增减和编辑子节点Tree。GitHub上看了一圈,没好用和合适的。索性就基于Ant DesignTree组件写一个。实现的效果如下:
可以增加子节点
可以删除子节点
可以编辑子节点信息
可以取消编辑信息
具体的效果图如下:
主要的就是借助 TreeNode 的 title 属性,它的类型是string|React...