React自研网格单列排序问题:点击第二列时首列排序图标消失
自研React网格组件多列排序异常问题
我正在为自研React网格组件添加排序功能,未使用任何第三方库构建网格及实现排序。当前组件仅支持单列排序:当尝试为两列启用排序功能后,点击第二列排序时,第一列的排序图标会消失。我正在排查排序实现逻辑,但无法定位问题根源。
排序功能核心源码
export const ORDER = { DESC: 'desc', ASC: 'asc' }; export class SortInfo { constructor({ columnId, order }) { this.columnId = columnId; this.order = order; } getColumnId() { return this.columnId; } setOrder(order) { return new SortInfo({ ...this, order }); } getOrder() { return this.order === ORDER.DESC ? ORDER.DESC : ORDER.ASC; } isValid(gridData) { return gridData.getHeaders().indexOf(this.columnId) >= 0; } isEmpty() { return this.columnId === undefined || this.columnId === null || this.columnId === ''; } isEqual(anotherSortInfo) { return ( anotherSortInfo && this.getColumnId() === anotherSortInfo.getColumnId() && this.getOrder() === anotherSortInfo.getOrder() ); } serialize() { const { columnId, order } = this; return { columnId, order }; } } function createSortInfo(columnId, order) { return new SortInfo({ columnId, order }); } export function createAscendingSortInfo(columnId) { return createSortInfo(columnId, ORDER.ASC); } export function createDescendingSortInfo(columnId) { return createSortInfo(columnId, ORDER.DESC); }
SortInfo的使用代码
function createGridHeaders(gridData, onSort) { const sortInfo = gridData.getSortInfo(); const sortId = sortInfo ? sortInfo.getColumnId() : undefined; gridData.getHeaders().map(id => ({headerName: new FieldRef(id, getGlobal).getLabel()})) return gridData .getHeaders() .map(id => ({ headerName: new FieldRef(id, getGlobal).getLabel(), field: id, cellRendererParams: { format: getCellFormatter(new FieldRef(id, getGlobal)) }, resizable: true, headerComponentParams: { sortOrder: id === sortId ? sortInfo.getOrder() : undefined }, onSort })); } const columns = gridData.getHeaders().length > 0 ? createGridHeaders(gridData, this.onSort) : undefined; return ( <GridPage className="sampleTable" title={title} subtitle={subtitle} buttons={gridButtons} onLoad={this.fetchData} gridData={gridData} columns={columns} > </GridPage> );
问题根源分析
- SortInfo仅支持单列存储:当前
SortInfo类只能保存单个列的排序信息,点击第二列时,新的SortInfo会直接覆盖旧的,导致第一列的排序状态完全丢失。 - 表头渲染依赖单一列ID:在
createGridHeaders中,仅通过sortId判断当前列是否显示排序图标,其他列直接设为undefined,切换列后之前的列自然失去图标。 - 排序触发逻辑无状态累积:虽然未展示
onSort实现,但可以推测点击新列时是直接替换整个SortInfo对象,而非在已有排序状态基础上添加新列的排序规则。
修复方案
1. 改造SortInfo为多列排序存储结构
将单例的SortInfo改为支持多列排序的集合结构:
export const ORDER = { DESC: 'desc', ASC: 'asc', NONE: 'none' }; export class MultiSortInfo { constructor(sortEntries = []) { this.sortEntries = sortEntries; } getOrder(columnId) { const entry = this.sortEntries.find(item => item.columnId === columnId); return entry?.order || ORDER.NONE; } toggleSort(columnId) { const currentOrder = this.getOrder(columnId); let newOrder; switch(currentOrder) { case ORDER.NONE: newOrder = ORDER.ASC; break; case ORDER.ASC: newOrder = ORDER.DESC; break; case ORDER.DESC: newOrder = ORDER.NONE; break; } const updatedEntries = newOrder !== ORDER.NONE ? [...this.sortEntries.filter(item => item.columnId !== columnId), {columnId, order: newOrder}] : this.sortEntries.filter(item => item.columnId !== columnId); return new MultiSortInfo(updatedEntries); } getSortEntries() { return [...this.sortEntries]; } serialize() { return this.sortEntries; } }
2. 更新表头渲染逻辑
针对每列单独查询排序状态,不再依赖单一sortId:
function createGridHeaders(gridData, onSort) { const multiSortInfo = gridData.getSortInfo(); return gridData .getHeaders() .map(id => ({ headerName: new FieldRef(id, getGlobal).getLabel(), field: id, cellRendererParams: { format: getCellFormatter(new FieldRef(id, getGlobal)) }, resizable: true, headerComponentParams: { sortOrder: multiSortInfo.getOrder(id) !== ORDER.NONE ? multiSortInfo.getOrder(id) : undefined }, onSort: () => onSort(id) })); }
3. 修改排序触发逻辑
调用MultiSortInfo的toggleSort方法累积排序状态,而非替换整个对象:
onSort = (columnId) => { const currentMultiSort = this.state.gridData.getSortInfo(); const newMultiSort = currentMultiSort.toggleSort(columnId); // 更新排序信息 this.setState(prevState => ({ gridData: {...prevState.gridData, sortInfo: newMultiSort} })); // 根据多列排序规则重新排序数据 const sortedData = this.sortGridData(this.state.gridData.getData(), newMultiSort); this.setState({ gridData: {...this.state.gridData, data: sortedData} }); } sortGridData(data, multiSortInfo) { const sortEntries = multiSortInfo.getSortEntries(); if (sortEntries.length === 0) return data; return [...data].sort((a, b) => { for (const {columnId, order} of sortEntries) { const valA = a[columnId]; const valB = b[columnId]; if (valA < valB) return order === ORDER.ASC ? -1 : 1; if (valA > valB) return order === ORDER.ASC ? 1 : -1; } return 0; }); }
内容的提问来源于stack exchange,提问作者user2128
相关产品推荐
相关产品推荐

