Käyttötarkoitus
useSortV2-hookilla voi järjestää objekteja sisältävän listan tietyn avaimen ja arvon perusteella. Sitä voi käyttää esimerkiksi taulukoiden tai muiden listamaisten esitystapojen järjestämiseen.
Oletuksena useSortV2-hook tukee seuraavien datatyyppien järjestämistä:
Teksti (string)
Numerot (number)
Päivämäärät (Date)
Tekstimuotoinen data järjestetään suomeksi lokalisoituna ja se järjestetään luonnollisen järjestyksen mukaisesti (Intl.Collator (Avautuu uuteen välilehteen) ).
Asetuksia voi muokata locale- ja collatorOptions-parametreilla.
Arvot null ja undefined järjestetään oletuksena ensimmäiseksi tai viimeiseksi riippuen valitusta järjestyksestä. Tähän voi vaikuttaa nullishOrder-parametrilla, jonka avulla ne voidaan järjestää myös aina ensimmäiseksi tai viimeiseksi.
Hook mahdollistaa myös järjestyksen räätälöinnin, jota voi hyödyntää monimutkaisempiin toteutuksiin. Katso esimerkki räätälöidyn järjestämisen toteuttamisesta .
Esimerkit
Taulukon järjestäminen
Esimerkki TableV2 -komponentilla toteutetun taulukon järjestämisestä.
function SortableTable() {
const headers = [
{
name: "Etuudet",
key: "name",
align: "left",
type: "string",
},
{
name: "2023 milj. €",
key: "year2023",
align: "right",
type: "number",
},
{
name: "2022 milj. €",
key: "year2022",
align: "right",
type: "number",
},
];
const rows = [
{
id: 1,
name: "Eläke-etuudet",
year2023: 2576.2,
year2022: 2476.6,
},
{
id: 2,
name: "Vammaistuet",
year2023: 622.0,
year2022: 573.9,
},
{
id: 3,
name: "Sairausvakuutusetuudet",
year2023: 4804.9,
year2022: 5032.6,
},
{
id: 4,
name: "Kuntoutus",
year2023: 785.4,
year2022: 713.2,
},
{
id: 5,
name: "Työttömyysetuudet",
year2023: 1933.5,
year2022: 1844.5,
},
{
id: 6,
name: "Lapsiperheiden etuudet",
year2023: 1819.0,
year2022: 1914.6,
},
];
const { data, sortKey, sortOrder, requestSort } = useSortV2(rows, {
locale: "fi",
});
const description = {
none: "ei järjestystä",
ascending: "järjestetty nousevasti",
descending: "järjestetty laskevasti",
};
const sortLabel = headers.find((el) => el.key === sortKey)?.name;
const sortDescription = description[sortOrder];
return (
<>
<div>
<p>
<strong>sortKey</strong>: {sortKey}
</p>
<p>
<strong>sortOrder</strong>: {sortOrder}
</p>
</div>
<TableV2 sortLabel={sortLabel} sortDescription={sortDescription}>
<TableV2Head>
<TableV2HeadRow>
{headers.map(({ key, name, align }) => (
<TableV2HeadCell
scope="col"
key={key}
align={align}
onClick={() => requestSort(key)}
order={sortKey === key ? sortOrder : null}
>
{name}
</TableV2HeadCell>
))}
</TableV2HeadRow>
</TableV2Head>
<TableV2Body>
{data.map((row) => (
<TableV2Row key={row.id}>
{headers.map(({ key, align, type }) => (
<TableV2Cell key={`${key}-${row.id}`} align={align}>
{type === "number" && new Intl.NumberFormat("fi").format(row[key])}
{type !== "number" && row[key]}
</TableV2Cell>
))}
</TableV2Row>
))}
</TableV2Body>
</TableV2>
</>
);
}
Oletusjärjestyksen asettaminen
useSortV2-hookille voidaan välittää defaultSort-parametri, joka asettaa oletusjärjestyksen, kun hook renderöidään ensimmäisen kerran.
Hookin palauttamaa setSort-funktiota voi hyödyntää järjestyksen asettamiseen halutuilla parametreilla.
function SortableTable() {
const headers = [
{
name: "Etuudet",
key: "name",
align: "left",
type: "string",
},
{
name: "2023 milj. €",
key: "year2023",
align: "right",
type: "number",
},
{
name: "2022 milj. €",
key: "year2022",
align: "right",
type: "number",
},
];
const rows = [
{
id: 1,
name: "Eläke-etuudet",
year2023: 2576.2,
year2022: 2476.6,
},
{
id: 2,
name: "Vammaistuet",
year2023: 622.0,
year2022: 573.9,
},
{
id: 3,
name: "Sairausvakuutusetuudet",
year2023: 4804.9,
year2022: 5032.6,
},
{
id: 4,
name: "Kuntoutus",
year2023: 785.4,
year2022: 713.2,
},
{
id: 5,
name: "Työttömyysetuudet",
year2023: 1933.5,
year2022: 1844.5,
},
{
id: 6,
name: "Lapsiperheiden etuudet",
year2023: 1819.0,
year2022: 1914.6,
},
];
const defaultSort = { key: "name", order: "ascending" };
const { data, sortKey, sortOrder, requestSort, setSort } = useSortV2(rows, {
locale: "fi",
defaultSort,
});
const description = {
none: "ei järjestystä",
ascending: "järjestetty nousevasti",
descending: "järjestetty laskevasti",
};
const sortLabel = headers.find((el) => el.key === sortKey)?.name;
const sortDescription = description[sortOrder];
return (
<>
<div>
<p>
<strong>sortKey</strong>: {sortKey}
</p>
<p>
<strong>sortOrder</strong>: {sortOrder}
</p>
<p>
<Button onClick={() => setSort(defaultSort.key, defaultSort.order)} variant="primary" appearance="outline">
Palauta oletus
</Button>
</p>
</div>
<TableV2 sortLabel={sortLabel} sortDescription={sortDescription}>
<TableV2Head>
<TableV2HeadRow>
{headers.map(({ key, name, align }) => (
<TableV2HeadCell
scope="col"
key={key}
align={align}
onClick={() => requestSort(key)}
order={sortKey === key ? sortOrder : null}
>
{name}
</TableV2HeadCell>
))}
</TableV2HeadRow>
</TableV2Head>
<TableV2Body>
{data.map((row) => (
<TableV2Row key={row.id}>
{headers.map(({ key, align, type }) => (
<TableV2Cell key={`${key}-${row.id}`} align={align}>
{type === "number" && new Intl.NumberFormat("fi").format(row[key])}
{type !== "number" && row[key]}
</TableV2Cell>
))}
</TableV2Row>
))}
</TableV2Body>
</TableV2>
</>
);
}
Järjestyksen kontrollointi hookin ulkopuolelta
Hookkia voi käyttää kontrolloidusti, jolloin järjestys välitetään hookille sort-parametrissa ja järjestystä päivitetään onChange-funktion avulla.
function SortableTable() {
const headers = [
{
name: "Etuudet",
key: "name",
align: "left",
type: "string",
},
{
name: "2023 milj. €",
key: "year2023",
align: "right",
type: "number",
},
{
name: "2022 milj. €",
key: "year2022",
align: "right",
type: "number",
},
];
const rows = [
{
id: 1,
name: "Eläke-etuudet",
year2023: 2576.2,
year2022: 2476.6,
},
{
id: 2,
name: "Vammaistuet",
year2023: 622.0,
year2022: 573.9,
},
{
id: 3,
name: "Sairausvakuutusetuudet",
year2023: 4804.9,
year2022: 5032.6,
},
{
id: 4,
name: "Kuntoutus",
year2023: 785.4,
year2022: 713.2,
},
{
id: 5,
name: "Työttömyysetuudet",
year2023: 1933.5,
year2022: 1844.5,
},
{
id: 6,
name: "Lapsiperheiden etuudet",
year2023: 1819.0,
year2022: 1914.6,
},
];
const defaultSort = {
key: "name",
order: "ascending",
};
const [sort, setSort] = useState(defaultSort);
const { data, requestSort } = useSortV2(rows, {
sort,
onChange: setSort,
});
const description = {
none: "ei järjestystä",
ascending: "järjestetty nousevasti",
descending: "järjestetty laskevasti",
};
const sortLabel = headers.find((el) => el.key === sort.key)?.name;
const sortDescription = description[sort.order];
return (
<>
<div>
<p>
<strong>sortKey</strong>: {sort.key}
</p>
<p>
<strong>sortOrder</strong>: {sort.order}
</p>
<p>
<Button onClick={() => setSort(defaultSort)} variant="primary" appearance="outline">
Palauta oletus
</Button>
</p>
</div>
<TableV2 sortLabel={sortLabel} sortDescription={sortDescription}>
<TableV2Head>
<TableV2HeadRow>
{headers.map(({ key, name, align }) => (
<TableV2HeadCell
scope="col"
key={key}
align={align}
onClick={() => requestSort(key)}
order={sort.key === key ? sort.order : null}
>
{name}
</TableV2HeadCell>
))}
</TableV2HeadRow>
</TableV2Head>
<TableV2Body>
{data.map((row) => (
<TableV2Row key={row.id}>
{headers.map(({ key, align, type }) => (
<TableV2Cell key={`${key}-${row.id}`} align={align}>
{type === "number" && new Intl.NumberFormat("fi").format(row[key])}
{type !== "number" && row[key]}
</TableV2Cell>
))}
</TableV2Row>
))}
</TableV2Body>
</TableV2>
</>
);
}
Järjestyksen räätälöinti
Räätälöidyn järjestyksen voi toteuttaa joko globaalilla tai avain-kohtaisella compare-funktiolla. Arvoista on myös mahdollista laskea yhdistelmiä getValue-funktiolla, jonka perusteella järjestäminen suoritetaan.
function SortableTable() {
const headers = [
{
name: "Etuudet",
key: "name",
align: "left",
type: "string",
},
{
name: "2023 milj. €",
key: "year2023",
align: "right",
type: "number",
},
{
name: "2022 milj. €",
key: "year2022",
align: "right",
type: "number",
},
{
name: "Muutos %",
key: "change",
align: "right",
type: "number",
},
];
const rows = [
{
id: 1,
name: "Eläke-etuudet",
year2023: 2576.2,
year2022: 2476.6,
},
{
id: 2,
name: "Vammaistuet",
year2023: 622.0,
year2022: 573.9,
},
{
id: 3,
name: "Sairausvakuutusetuudet",
year2023: 4804.9,
year2022: 5032.6,
},
{
id: 4,
name: "Kuntoutus",
year2023: 785.4,
year2022: 713.2,
},
{
id: 5,
name: "Työttömyysetuudet",
year2023: 1933.5,
year2022: 1844.5,
},
{
id: 6,
name: "Lapsiperheiden etuudet",
year2023: 1819.0,
year2022: 1914.6,
},
];
const getChangePercentage = ({ year2023, year2022 }) => {
return Number.parseFloat((((year2023 - year2022) / year2022) * 100).toFixed(1));
};
const formatNumber = new Intl.NumberFormat("fi").format;
// const { data, sortKey, sortOrder, requestSort } = useSortV2(rows, {
// getValue: getChangePercentage,
// compare(a, b) {
// return a - b;
// },
// });
const { data, sortKey, sortOrder, requestSort } = useSortV2(rows, {
fields: {
change: {
getValue: getChangePercentage,
compare(a, b) {
return a - b;
},
},
},
});
const description = {
none: "Ei järjestystä",
ascending: "Nouseva järjestys",
descending: "Laskeva järjestys",
};
const sortLabel = headers.find((el) => el.key === sortKey)?.name;
const sortDescription = description[sortOrder];
return (
<TableV2 sortLabel={sortLabel} sortDescription={sortDescription}>
<TableV2Head>
<TableV2HeadRow>
{headers.map(({ key, name, align }) => (
<TableV2HeadCell
scope="col"
key={key}
align={align}
onClick={key === "change" ? () => requestSort("change") : undefined}
order={key === "change" ? sortOrder : null}
>
{name}
</TableV2HeadCell>
))}
</TableV2HeadRow>
</TableV2Head>
<TableV2Body>
{data.map((row) => (
<TableV2Row key={row.id}>
{headers.map(({ key, align, type }) => (
<TableV2Cell key={`${key}-${row.id}`} align={align}>
{key !== "change" && type === "number" && formatNumber(row[key])}
{key !== "change" && type !== "number" && row[key]}
{key === "change" && formatNumber(getChangePercentage(row))}
</TableV2Cell>
))}
</TableV2Row>
))}
</TableV2Body>
</TableV2>
);
}