ant design table树形数据children数据异步获取


table表格支持这种树形可展开的形式,只需要在tableData中有children数据   不过这种用法是一开始获取表格数据时,就把children数据拿到了 实际场景中可能需要点击展开按钮时再去调取children数据
可以有两种方法实现这个需求
第一种: 通过expandable的onExpand方法,点击展开时获取数据,再通过筛选过滤,将数据添加到父级数据的children中
这里使用的是protable,antd table组件用法也是一样的.不过因为是通过改变tableData的数据,所以不要用request的方法赋值tableData
数据要求: 父级数据中需要一个字段表示当前的层级, 如果不是顶层数据,还要有一个字段表示父级id,方便添加数据时匹配
这里层级最多三级, 直接写了,如果不确定有几层的,需要写递归
import React, { useState, useEffect } from 'react';
import ProTable from '@ant-design/pro-table';
import { getCityList, getAreaList, getProvinces } from '@/services/citylist';
import { isEmpty } from 'lodash';

const TreeTable: React.FC = () => {
  const [tableData2, setTableData2] = useState([]);

  const colums: any[] = [
    {
      title: '省份',
      dataIndex: 'province',
      width: '20%',
      render: (val: string, recored: any) => {
        if (recored.city) return '-';
        return val;
      },
    },
    {
      title: '市区',
      dataIndex: 'city',
      width: '20%',
      render: (val: string, recored: any) => {
        if (recored.area) return '-';
        return val;
      },
    },
    {
      title: '区县',
      width: '20%',
      dataIndex: 'area',
    },
    {
      title: 'GDP(亿)',
      width: '19%',
      dataIndex: 'gdp',
      valueType: 'digit',
    },
    {
      title: '排名',
      width: '18%',
      dataIndex: 'rank',
    },
  ];

  // 获取树形数据
  const getData2 = async () => {
    const res: any = await getProvinces();

    setTableData2(res);
  };

  useEffect(() => {
    getData2();
  }, []);

  // 点击展开
  const areaExpandedRowsChange = async (expanded: boolean, record: any) => {
    console.log(expanded, record);
    // 做一下限制,如果已经有数据,不再重复请求数据
    if (expanded && record.children && isEmpty(record.children)) {
      if (record.level === 1) { // 获取第一级数据的children
        const res = await getCityList(record.province, 1);
        setTableData2(
          tableData2.map((item: any) => {
            if (item.id === record.id) {
              return {
                ...item,
                children: res,
              };
            }
            return item;
          }),
        );
      } else if (record.level === 2) { // 获取第二级数据的children
        const res = await getAreaList(record);
        setTableData2(
          tableData2.map((item: any) => {
            const obj = {
              ...item,
            };
            if (item.id === record.parentId) {
              item.children.forEach((ss: any) => {
                if (ss.id === record.id) {
                  ss.children = res;
                }
              });
            }
            return obj;
          }),
        );
      }
    }
  };

  return (
    <ProTable
      bordered
      columns={colums}
      rowKey="id"
      search={false}
      dataSource={tableData2}
      expandable={{
        onExpand: areaExpandedRowsChange,
      }}
      pagination={false}
      toolBarRender={false}
    />
  )
}
export default TreeTable;
这种方法在添加数据时,麻烦一点,但是展示和交互比较友好.适合层级确定,并且层级数比较少的情况 第二种方法: 通过expandable的expandedRowRender属性,返回自定义内容
这种可以方便的定义要展示的children数据,因为返回的是DOM, 这种层级可以嵌套,但是有几层数据必须确定
import React, { useState, useEffect } from 'react';
import ProTable from '@ant-design/pro-table';
import { getCityList, getAreaList, getProvinces } from '@/services/citylist';
import { isEmpty } from 'lodash';

const TreeTable: React.FC = () => {
  const [tableData2, setTableData2] = useState([]);

  const colums: any[] = [
    {
      title: '省份',
      dataIndex: 'province',
      width: '20%',
      render: (val: string, recored: any) => {
        if (recored.city) return '-';
        return val;
      },
    },
    {
      title: '市区',
      dataIndex: 'city',
      width: '20%',
      render: (val: string, recored: any) => {
        if (recored.area) return '-';
        return val;
      },
    },
    {
      title: '区县',
      width: '20%',
      dataIndex: 'area',
    },
    {
      title: 'GDP(亿)',
      width: '19%',
      dataIndex: 'gdp',
      valueType: 'digit',
    },
    {
      title: '排名',
      width: '18%',
      dataIndex: 'rank',
    },
  ];

  const colums2 = [
    {
      title: '',
      dataIndex: 'gdp',
      width: 45,
      render: () => '',
    },
    ...colums,
  ];

  // 获取表格数据
  const getData = () => {
    setTableData([
      {
        id: 1,
        province: '广东省',
        city: '',
        area: '',
        gdp: 7999,
      },
      {
        id: 2,
        province: '浙江省',
        city: '',
        area: '',
        gdp: 6990,
      },
      {
        id: 3,
        province: '江苏省',
        city: '',
        area: '',
        gdp: 5990,
      },
      {
        id: 4,
        province: '北京市',
        city: '',
        area: '',
        gdp: 8990,
      },
      {
        id: 5,
        province: '上海市',
        city: '',
        area: '',
        gdp: 8999,
      },
    ]);
  };

  useEffect(() => {
    getData();
  }, []);

  // 市渲染
  const provinceRender = (record: any) => {
    // 如果表格数据没变化,不会重新调接口,这里不需要再判断是否有值
    // 获取城市数据
    const getCitys = async () => {
      const res = await getCityList(record.province);
      return {
        data: res,
      };
    };

    // 区渲染
    const cityRender = (row: any) => {
      // 获取区数据
      const getAreas = async () => {
        const res = await getAreaList(row);
        return {
          data: res,
        };
      };

      return (
        <ProTable
          bordered
          columns={colums2}
          rowKey="id"
          search={false}
          request={getAreas}
          pagination={false}
          toolBarRender={false}
          showHeader={false}
        />
      );
    };

    return ( // 渲染的数据可以自定义
      <ProTable
        bordered
        columns={colums}
        rowKey="id"
        search={false}
        request={getCitys}
        expandable={{
          expandedRowRender: cityRender,
          // expandedRowKeys: cityRowKeys,
          // onExpandedRowsChange: cityExpandedRowsChange
        }}
        pagination={false}
        toolBarRender={false}
        showHeader={false}
      />
    );
  };

  return (
    <ProTable
      bordered
      columns={colums}
      rowKey="id"
      search={false}
      dataSource={tableData}
      expandable={{
        expandedRowRender: provinceRender,
        // expandedRowKeys: provinceRowKeys, // 如果需要筛选, 每次调用接口时将展开项收起,需要将expandedRowKeys属性设为可控,
        // onExpandedRowsChange: provinceExpandedRowsChange
      }}
      pagination={false}
      toolBarRender={false}
    />
  )
}
export default TreeTable;
这种方法不需要处理原始表格数据, 缺点是交互样式差一点, 展开按钮都在最左侧, 不能通过是否有下一级来区别展示展开图标  

总结: 这两种方式都可以异步获取子级数据,具体用那种可以根据实际应用场景选择   antd table的文档说明
源代码: https://github.com/shengbid/antdpro-demo/tree/main/src/pages/Table/treeTable