eduardweb.
shadcn/uiAvansat#nextjs#typescript#shadcn#react#tanstack-table

shadcn/ui și TanStack Table: Server-side pagination, sorting și filtering în Next.js

De Sorin Tudor, 28 iul. 2026 · 12 vizualizări · 3 like-uri

Postat 28 iul. 2026
typescript
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
import { useCallback } from 'react';

export function useServerTableParams() {
  const searchParams = useSearchParams();
  const router = useRouter();
  const pathname = usePathname();

  const page = Number(searchParams.get('page')) || 1;
  const limit = Number(searchParams.get('limit')) || 10;
  const sort = searchParams.get('sort') ?? 'createdAt';
  const order = searchParams.get('order') ?? 'desc';

  const setParams = useCallback((newParams: Record<string, string | number | null>) => {
    const params = new URLSearchParams(searchParams.toString());
    Object.entries(newParams).forEach(([key, value]) => {
      if (value === null || value === '') params.delete(key);
      else params.set(key, String(value));
    });
    router.push(`${pathname}?${params.toString()}`, { scroll: false });
  }, [searchParams, router, pathname]);

  return { page, limit, sort, order, setParams };
}

Salutare tuturor. Am văzut în ultima vreme tot mai multe proiecte în care lumea trage shadcn/ui data-table, copiază exemplul din docs și se miră de ce se blochează aplicația când baza de date trece de 10.000 de înregistrări. Dacă citești asta, probabil ai realizat deja că varianta lor implicită procesează totul în browser. Citirea acestui ghid îți va arăta cum să treci complet pe server-side execution folosind Next.js App Router și URL search params.

Implicit, TanStack Table încărcat ca la carte în ghidul shadcn face filtrările, sortarea și paginarea in-memory. Am avut anul trecut un proiect cu vreo 85k de comenzi și, mecanic, varianta client-side omora tab-ul de Chrome pe un MacBook M1. Soluția sănătoasă este să delegi totul către SQL (Prisma, Drizzle sau SQL chior) și să folosești URL-ul ca single source of truth.

Sync cu URL-ul: Fără useState local pentru starea tabelului

Regula de aur când faci server-side data table în Next.js: starea tabelului nu stă în React state, ci în query params (?page=2&sort=createdAt&order=desc&q=ion).

Dacă folosești state local, pierzi posibilitatea de a trimite link-ul exact unui coleg sau de a da refresh fără să pierzi contextul. În plus, la fiecare schimbare de pagină, trebuie doar să faci update la query string și să lase Server Component-ul să re-fetch-uiască datele din DB.

Pentru o experiență lină, poți folosi library-ul nuqs (type-safe search params) sau un hook custom simplu creat peste useSearchParams din next/navigation.

Trade-off-ul UX: Loading States vs. UI Flickering

Aici apare marea dilemă când treci pe server-side:

  1. Dacă folosești useTransition din React, tabelul rămâne vizibil cu datele vechi în timp ce datele noi se descarcă pe fundal, dar trebuie să afișezi un indicator discret de încărcare.
  2. Dacă te bazezi doar pe suspense.tsx, riști să sară layout-ul (flicker) la fiecare pagină dacă nu ai un skeleton calculat fix pe înălțimea tabelului.

La proiectul menționat mai devreme, am economisit peste 40% din timpul de randare inițial mutând calculul de pagination direct în PostgreSQL (cu LIMIT și OFFSET pe indecși corecți).

Partea mai nasoală? Search-ul debounced. Când utilizatorul tastează în input-ul de filtrare, nu vrei să faci request pe server la fiecare tastă apăsată. Trebuia neapărat un debounce de 300ms înainte de a actualiza URL-ul, altfel sufoci baza de date cu interogări parțiale inutil.

Cum legi useReactTable de starea din server

Trebuie să dezactivezi manual procesarea pe client prin setarea flag-urilor manualPagination: true, manualSorting: true și manualFiltering: true în opțiunile de la TanStack Table. Dacă uiți de ele, librăria va încerca din nou să pagineze local bucata de 10 rânduri pe care tocmai ai primit-o de pe server.

Voi cum gestionați starea filtrelor complexe? Mergeți pe URL query params sau preferați Server Actions cu starea salvată în session storage?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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