需求背景
我需要实现一个如下的多个相邻行合并为一行的功能,之后又接到需求,要求当用户切换冗余场景时,替换Table中的某一列的名称,具体如下截图所示
踩坑
我想到的办法是,当切换冗余场景时,将Table的columns进行序列化替换文本,于是写了以下代码:
let cols = JSON.parse(JSON.stringify(columns).replace(/:"总存储量"/g, ':"存储量"'));
setColumns(cols)
接着,setColumns成功,组件重新渲染,发现合并行失效了,文本替换也没有实时更新,变成和我的判断逻辑(汇总统计=总存储量,其他统计子类=存储量)相反了。
分析,为什么会如此
分两个原因描述
1、合并行为什么失效了?
因为antd的Table组件的columns是在初始化配置的时候一次性绑定的一个引用配置,因此,后续必须使用同一个引用配置columns才能使合并行效果生效,而我使用了序列化字符串再转回js对象,这个过程产生了新的引用,导致合并行的一些效果对应不上原先的配置,因此合并行效果失效
2、文本替换为什么没有即时生效,而是走了相反的判断逻辑结果?
如果我们没有使用setState去更新columns配置,就会组件不重新render,导致UI不能及时获取到最新的值,因此会产生我们拿到的值是上一次的值的情况
正确的做法
使用splice对原引用配置columns进行替换:
useEffect(() => {
if (isEqualRedd) {
columns.splice(7, 1, {
title: '总存储量',
dataIndex: 'sumStorgCap',
render: (text) => {
return text + 'T';
},
onCell: (_, index) => {
return {
rowSpan: _[`${'id'}RowSpan`],
};
},
});
_setColumns(columns);
} else {
columns.splice(7, 1, {
title: '存储量',
dataIndex: 'storgCap',
render: (text) => {
return text + 'G';
},
});
_setColumns(columns);
}
}, [navType, isEqualRedd]);
完整Table组件代码
import { Empty, Table } from 'antd';
import React, { useEffect, useState } from 'react';
import styles from './MergeCellTable.less';
const MergeCellTable = (props) => {
const { navType, pagination, onPageChange, isEqualRedd } = props;
const [data, setData] = useState([]);
const [_columns, _setColumns] = useState([]);
let columns = [
{
title: 'key',
dataIndex: 'key',
className: styles.notShowCol,
},
{
title: '编号',
dataIndex: 'id',
onCell: (_, index) => {
return {
rowSpan: _[`${'id'}RowSpan`],
};
},
},
{
title: '治理优先级',
dataIndex: 'govPrior',
onCell: (_, index) => {
return {
rowSpan: _[`${'id'}RowSpan`],
};
},
},
{
title: '资产名',
dataIndex: 'astNm',
},
{
title: '所属中心',
dataIndex: 'blngCtr',
},
{
title: '责任人',
dataIndex: 'princ',
},
{
title: '冗余场景',
dataIndex: 'redundSmlClass',
},
{
title: '总存储量',
dataIndex: 'sumStorgCap',
render: (text) => {
return text + 'T';
},
onCell: (_, index) => {
return {
rowSpan: _[`${'id'}RowSpan`],
};
},
},
{
title: '冗余类型',
dataIndex: 'redundType',
onCell: (_, index) => {
return {
rowSpan: _[`${'id'}RowSpan`],
};
},
},
];
useEffect(() => {
setData(props.dataSet);
}, [props.dataSet]);
useEffect(() => {
if (navType === '其他') {
columns.splice(4, 1, {
title: '所属团队',
dataIndex: 'blngCtr',
});
} else {
columns.splice(4, 1, {
title: '所属中心',
dataIndex: 'blngCtr',
});
}
_setColumns(columns);
}, [navType, isEqualRedd]);
useEffect(() => {
if (isEqualRedd) {
columns.splice(7, 1, {
title: '总存储量',
dataIndex: 'sumStorgCap',
render: (text) => {
return text + 'T';
},
onCell: (_, index) => {
return {
rowSpan: _[`${'id'}RowSpan`],
};
},
});
_setColumns(columns);
} else {
columns.splice(7, 1, {
title: '存储量',
dataIndex: 'storgCap',
render: (text) => {
return text + 'G';
},
});
_setColumns(columns);
}
}, [navType, isEqualRedd]);
const onChange = (page) => {
onPageChange && onPageChange(page);
};
return (
<Table
columns={_columns}
dataSource={data}
bordered
pagination={false}
rowClassName={(record, index) => (index % 2 === 1 ? 'even' : 'odd')}
onChange={onChange}
locale={{
emptyText: (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据" />
),
}}
/>
);
};
export default MergeCellTable;