The sort that never leaves the page
don't
const { rows } = useLoaderData<typeof loader>()
const [query, setQuery] = useState(emptyQuery)
const sorted = useMemo(
() => (query.sort.length ? [...rows].sort(compare(query.sort)) : rows),
[rows, query.sort],
)
return (
<ServerTable
aria-label="Orders"
columns={columns}
rows={sorted}
query={query}
onQueryChange={setQuery}
getRowId={(o) => String(o.id)}
/>
)do
// the loader reads the params and puts them in the ORDER BY
const { rows, total } = useLoaderData<typeof loader>()
const [params, setParams] = useSearchParams()
const query = queryFromSearchParams(params, filterableColumns)
return (
<ServerTable
aria-label="Orders"
columns={columns}
rows={rows}
total={total}
query={query}
onQueryChange={(next) => {
setParams(new URLSearchParams(queryToSearchParams(next)))
}}
tiebreakColumn="id"
getRowId={(o) => String(o.id)}
/>
)The wrong version is shorter by one loader argument and wrong by a whole dataset. The right one also gets a shareable URL and a working back button for free, because the sort now lives where the query does — and `queryFromSearchParams` runs in the loader, because @/lib/data-table has no React in it.