eduardweb.
shadcn/uiAvansat#nextjs#react#shadcn-ui#server-side#tanstack-table

Cum faci corect server-side pagination și filtering cu shadcn/ui și TanStack Table

De Marian Apostol, 28 apr. 2026 · 2 vizualizări · 3 like-uri

Postat acum 2 zile
typescript
const table = useReactTable({
  data,
  columns,
  pageCount: Math.ceil(totalCount / pageSize),
  state: {
    pagination: { pageIndex, pageSize },
    sorting,
  },
  onPaginationChange: (updater) => {
    const nextState = typeof updater === 'function' ? updater({ pageIndex, pageSize }) : updater;
    const params = new URLSearchParams(searchParams);
    params.set('page', (nextState.pageIndex + 1).toString());
    params.set('size', nextState.pageSize.toString());
    router.push(`${pathname}?${params.toString()}`);
  },
  manualPagination: true,
  getCoreRowModel: getCoreRowModel(),
});

Dacă folosești shadcn/ui, sigur ai dat peste componenta de DataTable. E mișto, arată bine, dar exemplul din documentație e făcut 90% pentru client-side. Când ai 50 de rânduri e parfum, dar am avut un proiect recent cu peste 12.000 de înregistrări într-un CRM și client-side filtering-ul pur și simplu a îngenuncheat browserul.

Problema e că mulți developeri copiază exemplul din docs și se miră de ce aplicația se mișcă greu sau de ce nu pot trimite un link către o anumită pagină din tabel. Soluția e să muți toată starea (pagina, sortarea, filtrele) în URL.

De ce să te complici cu Server-Side?

Primul trade-off e evident: scrii mai mult cod. Mult mai mult. Trebuie să gestionezi manual starea tabelei și să o sincronizezi cu searchParams din Next.js. Dar beneficiile sunt uriașe. La proiectul menționat mai sus, am redus timpul de interacțiune (TTI) cu vreo 40% pe dispozitivele mobile mai slabe pentru că browserul nu mai trebuia să proceseze un JSON gigant în memorie.

În plus, ai „shareability”. Dacă un coleg te întreabă de o factură de anul trecut, îi trimiți URL-ul cu filtrele deja aplicate. Dacă totul e pe client, el vede tabelul gol când deschide link-ul.

Sincronizarea cu URL-ul

Secretul stă în opțiunile manualPagination, manualSorting și manualFiltering din hook-ul useReactTable. Când le pui pe true, TanStack Table nu mai face nimic automat. Tu devii responsabil să tragi datele din baza de date (sau API) pe baza parametrilor din URL.

Am pățit să mă bat cu useEffect pentru a actualiza URL-ul când se schimbă pagina, dar e o abordare proastă. Mai bine folosești un handler care dă router.push direct pe evenimentele de onPaginationChange. Astfel, Next.js face fetch-ul pe server, componenta primește datele noi prin props și totul rămâne sincronizat fără loop-uri infinite de randări.

Trade-off-uri sincere

Nu e totul roz. UX-ul poate avea de suferit dacă nu pui un loading state calumea. Pe client-side, filtrarea e instantanee. Pe server-side, ai latența rețelei. Eu am rezolvat asta cu un useTransition din React. Când userul tastează în search, UI-ul rămâne responsiv, iar tabelul intră într-o stare de „pending” (opacity 0.5) până vin datele noi.

Un alt aspect e complexitatea query-urilor de SQL/Prisma. Trebuie să fii atent la indexare. Degeaba ai mutat filtrarea pe server dacă baza de date face un full scan la fiecare apăsare de tastă în search box.

În concluzie, dacă ai sub 500 de rânduri, rămâi pe client-side. E mai simplu și mai rapid de implementat. Dar dacă vrei o aplicație enterprise care să nu crape la prima interogare serioasă, server-side-ul e singura cale sănătoasă.

Voi cum gestionați starea filtrelor complexe? Le țineți în URL sau preferați un state management global gen Zustand?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.