import {
useReactTable,
getCoreRowModel,
PaginationState,
} from "@tanstack/react-table";
import { useRouter, usePathname, useSearchParams } from "next/navigation";
interface ServerTableProps {
data: any[];
pageCount: number;
}
export function ServerDataTable({ data, pageCount }: ServerTableProps) {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const page = Number(searchParams.get("page")) || 1;
const pageSize = Number(searchParams.get("limit")) || 10;
const paginationState: PaginationState = {
pageIndex: page - 1,
pageSize,
};
const table = useReactTable({
data,
pageCount,
state: { pagination: paginationState },
onPaginationChange: (updater) => {
const nextState = typeof updater === "function" ? updater(paginationState) : updater;
const params = new URLSearchParams(searchParams.toString());
params.set("page", String(nextState.pageIndex + 1));
params.set("limit", String(nextState.pageSize));
router.push(`${pathname}?${params.toString()}`);
},
manualPagination: true,
getCoreRowModel: getCoreRowModel(),
});
return (
// Renders table with table.getRowModel()
null
);
}Să fim serioși: ghidul oficial shadcn/ui pentru DataTable e genial ca să pornești la drum, dar e gândit aproape exclusiv pentru filtrare și paginare client-side. Când ai de-a face cu seturi mari de date, abordarea asta devine rapid un coșmar de performanță.
Am avut recent de implementat un dashboard de administrare pentru un client cu peste 85.000 de înregistrări în baza de date. Dacă încărcam totul în browser din prima, nu doar că omoram memoria userului, dar timpul de încărcare inițial sărea lejer de 5 secunde. Mutarea întregii logici pe server (Next.js App Router + TanStack Table) a redus timpul de încărcare la doar 130ms.
De ce e greșită starea locală (useState)
Cea mai mare greșeală pe care o văd în proiecte este folosirea stării locale (useState) din React pentru paginare și sortare, în timp ce datele sunt aduse de pe server.
Dacă userul sortează după coloana „Nume”, se duce pe pagina 3, iar apoi dă un simplu refresh la pagină, surpriză: revine la pagina 1, nesortată. UX-ul este complet distrus.
Soluția corectă este să tratăm URL-ul ca single source of truth. Parametrii precum page, limit, sort și search trebuie să trăiască în URL sub formă de query params (?page=3&sort=name-desc).
Sincronizarea TanStack Table cu URL-ul
Ca să-i spui lui TanStack Table că tu te ocupi de calcule și că el trebuie doar să randeze ce-i dai, trebuie să activezi modul manual. Asta înseamnă să-i treci proprietățile manualPagination: true, manualSorting: true și manualFiltering: true în configurare.
Iată cum se schimbă fluxul:
- Userul dă click pe „Pagina următoare”.
- Interceptezi evenimentul și updatezi URL-ul folosind
router.push('/dashboard?page=2'). - Next.js simte schimbarea, re-execută Server Component-ul care face query-ul în baza de date cu noii parametri.
- Pagina se randează din nou cu noile date proaspete.
Trade-off-ul sincer: Boilerplate vs Performanță
Nu o să vă mint, implementarea asta vine cu un cost destul de mare în linii de cod scrise. Spre deosebire de varianta client-side unde TanStack face toată magia „out of the box”, aici trebuie să scrii tu parserul de query params, să validezi inputurile (recomand cu căldură biblioteca nuqs sau un simplu parser cu zod) și să te asiguri că baza de date are indeicși puși corect pe coloanele după care se face sortarea sau filtrarea.
În plus, trebuie să fii extrem de atent la debouncing pe inputul de căutare. Dacă trimiți un request la server la fiecare tastă apăsată, o să-ți bombardezi baza de date cu query-uri inutile. Un debounce de 300ms la nivel de client este obligatoriu înainte de a împinge noul query param în URL.
La final de zi, efortul merită din plin. Tabela devine incredibil de rapidă, link-urile pot fi partajate direct între colegi cu filtrele deja aplicate, iar serverul tău nu va mai transpira încercând să trimită megabiți întregi de JSON pe client.
Cum gestionați voi stările astea complexe în Next.js? Mergeți pe varianta clasică cu useTransition sau folosiți librării dedicate pentru query params?