recursive multicolumn sort in react
This comes with a little regex magic to allow sorting numbers with an optional unit appended. The state variable sortBy is an array of simple obects with keys key and order
useEffect(() => {
const unitregex = /(\d+\.\d+|\d+)([^\d.]+)/;
const sortFunctions = {
number: (a, b) => {
const unitA = isNaN(Number(a)) ? a.match(unitregex)?.[2] : null;
const unitB = isNaN(Number(b)) ? b.match(unitregex)?.[2] : null;
if (unitA && unitB) {
return Number(a.split(unitA)[0]) > Number(b.split(unitB)[0])
? 1
: Number(a.split(unitA)[0]) < Number(b.split(unitB)[0])
? -1
: 0;
} else {
return Number(a) > Number(b) ? 1 : Number(a) < Number(b) ? -1 : 0;
}
},
default: (a, b) => {
return a > b ? 1 : a < b ? -1 : 0;
},
};
const metaSort = (a, b) => {
let depth = sortBy.length;
// eslint-disable-next-line
const innerSort = (a, b) => {
const sortingBy = sortBy[sortBy.length - depth];
let res = (sortFunctions[
columns.filter((c) => c.key === sortingBy.key)[0].filter.type
] || sortFunctions['default'])(a[sortingBy.key], b[sortingBy.key]);
if (sortingBy.order === "descending") {
res = res > 0 ? -1 : res < 0 ? 1 : 0;
}
if (res === 0 && depth > 1) {
depth = depth - 1;
res = innerSort(a, b);
}
return res;
};
return innerSort(a,b);
};
setSortedRows(rows.slice(0).sort(metaSort));
}, [sortBy, columns, rows]);
