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]);