有一个需求是可以使主表格里每一栏数据展开,在子table里显示与其相关的子数据项,展开的时候去向后台请求数据。
另外如果请求的数据不存在则要不显示展开按钮。
用的组件库是Antd。
首先我们看Antd官方文档的Table有嵌套子表格的功能,
可见我们需要使用expandedRowRender参数,但是尝试在expandedRowRender函数中进行请求,会发现发出了连续的请求,所以我们把请求写在onExpand中,只在点击展开图表的时候发出一次。
<Table
expandIcon={expandIcon}
onExpand={this.onExpand}
expandedRowRender={record => expandedRowRender(record)}
expandRowByClick="true"
columns={columns}
dataSource={records}
rowKey={record => `${record.id}record`}
style={{ backgroundColor: '#fff', marginTop: 16 }}
/>
之后我们写onExpand函数,注意这里的参数要写上expanded,代表是展开还是合并,我之前没写这个参数,只写了record,就一直无法接受到真正的record,record总是显示true或者false,后来又去看官方文档才发现这个问题。
onExpand = (expanded, record) => {
const { actions } = this.props;
const rid = record.id;
actions.fetchProcess(rid);
}
我们在action中请求数据,在reducer中改变状态。
function receiveProcess(processRecords) {
return {
type: at.PROCESS,
processRecords,
receivedAt: Date.now(),
};
}
export const fetchProcess = id => async (dispatch) => {
axios.get(`YOUR URL`).then((resp) => {
dispatch(receiveProcess(resp.data));
})
.catch(({ response }) => dispatch(Notification(response)));
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case at.RECEIVE_RECORD:
return Object.assign({}, state, { records: action.data });
case at.PROCESS: {
return Object.assign({}, state, {
process: {
...state.process,
[action.processRecords[0].id]: action.processRecords,
},
});
}
....
这里需要注意的一个点就是,我们用了id来作为key,对应的value为我们要展开的数据,这样存数据,用父数据项的id去选择需要的数据,就不会出现展开的子table数据一样的问题。ANTD里也有一个参数expandedRowKeys有相同功能。
在收回展开的时候,也就是expanded===false的时候,可以将对应id的数据清空,防止数据冗余。
最后我们写expandedRowRender函数,拿到数据,渲染子表。
const expandedRowRender = (rrecord) => {
let { process } = this.props;
const { id } = rrecord;
if (process) {
if (process[id]) {
process = process[id];
const columns = [];
if (process[0].service_name !== null) {
columns.push(
{
.......
}
);
return (
<Table
columns={columns}
dataSource={process}
rowKey={record => `${record.id}record`}
pagination={false}
/>
);
}
}
return null;
};
在这里睬的坑是每次点击请求的时候,发现调用了两次expandedRowRender,第一次的时候还没有拿到新数据,第二次才有,所以加了if判断对应的数据是否拿到。
然后要实现数据不存在的时候点击图标不显示
const expandIcon = (props) => {
if (props.record.record_eid) {
if (props.expanded) {
return ( // eslint-disable-next-line
<a
style={{ color: 'black' }}
onClick={(e) => {
props.onExpand(props.record, e);
}}
>
<Icon type="minus" className="minus-square" />
</a>
);
}
return ( // eslint-disable-next-line
<a
style={{ color: 'black' }}
onClick={(e) => {
props.onExpand(props.record, e);
}}
>
<Icon type="plus" className="plus-square" />
</a>
);
}
return (<a onClick={(e) => e.preventDefault()} />); // eslint-disable-line
};
效果如图
今天的分享就到这里了,小菜刚刚学习前端,如果有发现我代码有问题的或者有更优雅写法的,希望不吝赐教,万分感谢。