I've been struggling with this issue for a while. I would like to enable multi-column sort in react-data-grid. I cloned the repository and tried to implement a similar solution to what they had. This is what I came up with:
import DataGrid from 'react-data-grid'
...
export const CustomizedTable = (props: VialTableProps) => {
const { className, columnDefs, groupBy, onCellClicked, rowData, rowHeight } =
props
const { onSortColumnsChange, sortColumns } = props
const [expandedGroupIds, setExpandedGroupIds] = useState(
(): ReadonlySet<unknown> => new Set<unknown>([])
)
const handleSort = (columnKey: string, direction: SortDirection) => {
console.log('handleSort:', columnKey, direction)
const existingSort = sortColumns.find(sc => sc.columnKey === columnKey)
console.log('iniital order', existingSort)
if (existingSort) {
if (existingSort.direction === 'ASC') {
direction = 'DESC'
} else if (existingSort.direction === 'DESC') {
const newSortColumns = sortColumns.filter(
sc => sc.columnKey !== columnKey
)
if (onSortColumnsChange) {
onSortColumnsChange(newSortColumns)
}
return
}
} else {
direction = 'ASC'
}
console.log('new direction', direction)
const newSortColumn: SortColumn = {
columnKey,
direction,
}
if (onSortColumnsChange) {
onSortColumnsChange([newSortColumn])
}
}
return (
<DataGrid
...
sortColumns={sortColumns}
onSortColumnsChange={handleSort}
/>
</div>
)
}
I reuse this table here:
...
const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([])
function getComparator(sortColumn: SortColumn) {
if (Array.isArray(sortColumn.columnKey)) {
sortColumn = sortColumn.columnKey[0]
}
switch (sortColumn.columnKey) {
case '***':
case '***':
case '***':
case '***':
case '***':
return (
a: { [x: string]: string },
b: { [x: string]: string }
) => {
if (
typeof a[sortColumn.columnKey] === 'string' &&
typeof b[sortColumn.columnKey] === 'string'
) {
if (sortColumn.direction === 'ASC') {
return (a[sortColumn.columnKey] as string).localeCompare(
b[sortColumn.columnKey] as string
)
} else {
return (b[sortColumn.columnKey] as string).localeCompare(
a[sortColumn.columnKey] as string
)
}
} else {
return 0
}
}
case 'subjectStatus':
case 'queriesStatus':
return (
a: { [x: string]: { code: string } },
b: { [x: string]: { code: string } }
) => {
if (sortColumn.direction === 'ASC') {
return a[sortColumn.columnKey].code.localeCompare(
b[sortColumn.columnKey].code
)
} else {
return b[sortColumn.columnKey].code.localeCompare(
a[sortColumn.columnKey].code
)
}
}
default:
throw new Error(`unsupported sortColumn: "${sortColumn.columnKey}"`)
}
}
const sortedRows = useMemo(() => {
console.log('useMemo called', sortColumns)
if (sortColumns.length === 0) return subjectRows
return [...subjectRows].sort((a, b) => {
for (const sort of sortColumns) {
const comparator = getComparator(sort)
const compResult = comparator(a, b)
if (compResult !== 0) {
return sort.direction === 'ASC' ? compResult : -compResult
}
}
return 0
})
}, [subjectRows, sortColumns])
console.log('sortedRows:', sortedRows)
return (
<CustomizedTable
rowData={sortedRows}
...
sortColumns={sortColumns}
onSortColumnsChange={setSortColumns}
/>
)
}
These are the console logs I see:
When I click a column header the first time, the rows are correctly sorted in ascending order:
- handleSort: [{…}]0: {columnKey: '***', direction: 'ASC'}length: 1[[Prototype]]: Array(0) undefined index.tsx:47 iniital order undefined index.tsx:65 new direction ASC
When I click the same column header a second time, no sorting occurs:
handleSort: [{…}]0: {columnKey: '***', direction: 'ASC'}length: 1[[Prototype]]: Array(0) undefined
index.tsx:47 iniital order undefined
index.tsx:65 new direction ASC
My ideal behavior is that; if I click a column header once, all rows should be sorted in ascending order, a second time in descending order and a third time revert to the default