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<any[]>([]); 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<any[]>([]); 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的文档说明