43 lines
1.2 KiB
TypeScript
43 lines
1.2 KiB
TypeScript
import { useState, useMemo } from 'react';
|
|
|
|
export type SortDir = 'asc' | 'desc';
|
|
|
|
export function useSort<T extends Record<string, any>>(
|
|
data: T[],
|
|
defaultKey: keyof T,
|
|
defaultDir: SortDir = 'desc'
|
|
): {
|
|
sorted: T[];
|
|
sortKey: keyof T;
|
|
sortDir: SortDir;
|
|
handleSort: (key: keyof T) => void;
|
|
} {
|
|
const [sortKey, setSortKey] = useState<keyof T>(defaultKey);
|
|
const [sortDir, setSortDir] = useState<SortDir>(defaultDir);
|
|
|
|
const handleSort = (key: keyof T) => {
|
|
if (key === sortKey) {
|
|
setSortDir((prev) => (prev === 'asc' ? 'desc' : 'asc'));
|
|
} else {
|
|
setSortKey(key);
|
|
setSortDir('desc');
|
|
}
|
|
};
|
|
|
|
const sorted = useMemo(() => {
|
|
return [...data].sort((a, b) => {
|
|
const av = a[sortKey];
|
|
const bv = b[sortKey];
|
|
let cmp = 0;
|
|
if (av == null && bv == null) cmp = 0;
|
|
else if (av == null) cmp = 1;
|
|
else if (bv == null) cmp = -1;
|
|
else if (typeof av === 'number' && typeof bv === 'number') cmp = av - bv;
|
|
else cmp = String(av).localeCompare(String(bv));
|
|
return sortDir === 'desc' ? -cmp : cmp;
|
|
});
|
|
}, [data, sortKey, sortDir]);
|
|
|
|
return { sorted, sortKey, sortDir, handleSort };
|
|
}
|