Інтерактивні таблиці на TanStack Table: де ламається логіка
Саморобна таблиця ламається передбачувано: сортування, фільтри, пагінація та виділення рядків живуть у різних місцях — у стані компонента, у ref, у замиканнях обробників.
Варто додати віртуалізацію або серверне підвантаження, і ці частини починають сперечатися одна з одною: фільтр скидається при перемальовуванні, виділення «переїжджає» на інші рядки після сортування, а лічильник показує одне, тоді як на екрані інше. Кожен такий дефект шукається довго, бо джерело істини розмазане по десятку місць.
Друга точка відмови — продуктивність рендера. Поки рядків сотня, все непомітно. На вибірці в кілька тисяч браузер починає перемальовувати весь набір при кожному натисканні клавіші в полі пошуку, і інтерфейс завмирає на секунди.
Лікується це не «оптимізацією потім», а архітектурою: модель стану таблиці, мемоізація рядків, віртуалізація вікна та розділення клієнтської і серверної обробки даних.
TanStack Table якраз про це: він не малює розмітку за вас, а тримає стан таблиці — сортування, фільтри, групування, вибір рядків, пагінацію — в одному передбачуваному місці.
Ви отримуєте контроль над рендером і явні точки, куди підключати серверні запити, не втрачаючи фільтри при оновленні даних. Розбираємо, як це закривається на практиці: від моделі даних до відкату невдалого релізу.
Що дає керована таблиця: швидкість, стабільність, передбачуваність
Керована модель — це коли стан таблиці (сортування, фільтри, пагінація, виділення рядків) живе в одному місці, а не розмазаний по десятках обробників усередині компонента.
Ми тримаємо його в контрольованому сховищі й передаємо в таблицю як вхідні дані — інтерфейс перестає «здогадуватися» про поточний стан і завжди малює рівно те, що в моделі.
Практичний ефект видно на обсязі даних: на вибірках у десятки тисяч рядків сортування за колонкою вкладається в частки секунди, бо перерахунок іде за індексами, а не повним перебором на кожен рендер.
Зависання під час перемикання фільтрів і прокручування зникають: важкі обчислення винесені з циклу відмальовування, а рядки з'являються в міру необхідності, а не всі одразу.
Коду стає помітно менше. Логіка вибірки, сортування й пагінації описана декларативно — один набір правил замість розсипу умов, тому доопрацювання «додати колонку з обчислюваним полем» займає години, а не дні. Новий інженер входить у таблицю за описом моделі, а не за читанням усього компонента.
Навантаження на браузер перестає зростати разом із числом рядків: пам'ять тримається на стабільному рівні, а інтерфейс однаково чутливий і на сотні записів, і на великій вибірці.
Окремо закриваємо крайні випадки — порожній результат, помилка завантаження, довга відповідь сервера: користувач бачить зрозумілий стан, а не застиглий екран.
Підтримуваність тримається на передбачуваності: правила фільтрації та сортування можна покрити перевірками окремо від відмальовування, а поведінка таблиці відтворюється в тестах без ручного кліку по інтерфейсу.
Режими роботи таблиці: клієнтський, серверний, гібридний
Режим визначається не розміром таблиці, а тим, де живуть дані та хто ними керує. Клієнтський режим тримає весь набір у пам'яті браузера: сортування, фільтри та пагінація обчислюються на місці, відповідь на дію миттєва.
Стеля — обсяг вибірки: до кількох тисяч рядків це комфортно, далі пам'ять і первинне відображення починають помітно гальмувати.
Серверна пагінація перекладає зріз, сортування та фільтрацію на бекенд: браузер отримує лише поточну сторінку. Так працюють довідники на сотні тисяч записів, але кожна дія — мережевий запит, і за повільного каналу інтерфейс «підвисає» між кліками. Пом'якшує це попереднє завантаження сусідніх сторінок і кеш уже переглянутих зрізів.
Гібридний режим бере найкраще з двох: фільтри та сортування виконує сервер, а пагінацію та візуалізацію рядків — клієнт. У пам'яті тримається обмежений набір, довгі списки рендеряться вікном, і прокручування залишається плавним навіть на десятках тисяч рядків.
| Режим | Коли підходить | Обмеження |
|---|---|---|
| Клієнтський | До кількох тисяч рядків, дані змінюються рідко | Зростання пам'яті, просідання первинного відображення |
| Серверний | Великі довідники, часті оновлення | Затримка на кожен запит, потрібен стабільний канал |
| Гібридний | Тисячі рядків із фільтрами та сортуванням | Складніша синхронізація стану клієнта та сервера |
Вибір фіксуємо на етапі проєктування: перемикання режиму пізніше зачіпає і клієнтську логіку, і контракти API.
Етапи впровадження: від аудиту поточної таблиці до передачі
Робота над інтерактивною таблицею починається не з коду, а з розбору того, що вже є: як влаштована поточна таблиця, де вона гальмує на великих вибірках, які сценарії фільтрації та сортування реально використовують люди, а які залишилися «про всяк випадок».
Такий аудит таблиці показує, що переписувати, а що достатньо переналаштувати — і одразу задає межі задачі.
Далі проєктуємо модель стану: що живе в адресованих параметрах (фільтри, сортування, сторінка), що — локально, як дані підвантажуються посторінково і кешуються.
Від цієї схеми залежить, чи переживе таблиця перезавантаження сторінки і чи повернеться користувач до того самого вигляду.
- Аудит таблиці. Дивимося поточний код, заміряємо поведінку на реальних обсягах, фіксуємо вузькі місця та список того, що зберігаємо без змін.
- Проєктування моделі стану. Визначаємо, які параметри синхронізуються з адресою, як влаштовані вибір рядків, групування та розкриття рядків, де зберігається стан.
- Налаштування колонок. Описуємо колонки декларативно: ширини, закріплення, порядок, видимість, форматування комірок, кастомні рендери для складних типів даних.
- Складання взаємодій. Підключаємо сортування, фільтри, пошук, пагінацію та віртуалізацію довгих списків так, щоб важкі вибірки не блокували інтерфейс.
- Перевірка на даних. Проганяємо таблицю на бойових вигрузках: граничні значення, порожні відповіді, повільні запити, поведінка при збої завантаження.
- Документація та передача коду. Оформлюємо структуру компонентів, описуємо конфігурацію колонок і модель стану, щоб команда замовника могла додавати колонки та правила без нас.
- Супровід після запуску. Стежимо за поведінкою на реальному трафіку, доналаштовуємо продуктивність і закриваємо зворотний зв'язок від користувачів.
Кожен етап закінчується перевірюваним результатом, а не звітом про виконану роботу. Передача коду включає не лише репозиторій, а й зрозумілу схему, за якою таблицю можна розвивати далі.
Налаштування колонок, фільтрів і сортування під ваш сценарій
Налаштування починається з опису колонок: для кожної задається тип даних, спосіб відображення та правила обчислення. Числові колонки отримують вирівнювання та форматування розрядів, дати — єдиний формат і часовий пояс, текстові — обрізання з розкриттям за кліком.
Обчислювані колонки (наприклад, маржа або відхилення від плану) розраховуються на стороні клієнта без повторного запиту до сервера, тому перерахунок під час фільтрації відбувається миттєво.
Фільтрація будується як складена: кілька умов об'єднуються логікою «і/або», кожна прив'язана до своєї колонки та типу порівняння — діапазон, входження до списку, підрядок.
Стан фільтрів і сортування зберігається в адресному рядку, тому посилання на конкретну вибірку можна передати колезі або зберегти як подання.
Сортування підтримує кілька рівнів: спочатку за підрозділом, усередині — за датою, потім за сумою; порядок рівнів користувач змінює перетягуванням.
- Типи колонок — текст, число, дата, статус, обчислюване значення; від типу залежать редактор комірки та правила порівняння.
- Складені фільтри — набір умов із логікою «і/або», збереження наборів як іменованих подань.
- Багаторівневе сортування — до кількох ключів одночасно з наочним порядком пріоритетів.
- Групування рядків — згортання за категорією з агрегатами (сума, середнє, кількість) на рівні групи.
- Закріплення колонок — ключові стовпці залишаються на екрані під час горизонтального прокручування широкої таблиці.
- Умовне форматування — підсвічування комірок і рядків за порогами: прострочення, від'ємні відхилення, вихід за ліміт.
- Редагування та валідація — правка комірок прямо в таблиці з перевіркою значень до відправлення на сервер.
Візуальна частина налаштовується окремо від логіки: щільність рядків, видимість колонок, порядок і ширину користувач зберігає у своєму профілі.
В основі — TanStack Table, бібліотека без нав'язаної верстки: розмітку та стилі ми пишемо під ваш інтерфейс, а не підлаштовуємо інтерфейс під готовий компонент. Це дозволяє зберегти єдиний вигляд з іншими екранами продукту.
Що замовник отримує після впровадження
Впровадження завершується не демонстрацією працюючої таблиці, а набором артефактів, за якими ваша команда зможе її розвивати без нас. Нижче — що саме передаємо.
- Конфігурація таблиці — опис колонок, типів даних, сортування, фільтрів і групувань у декларативному вигляді. Нова колонка додається правкою одного опису, а не переписуванням логіки рендерингу.
- Схема моделі стану — карта того, де живе сортування, пагінація, виділення рядків і розкриті групи: що в адресі сторінки, що в локальному стані, що йде на сервер. За нею видно, чому фільтр не скидається при переході та як відтворити стан таблиці посиланням.
- Регламент розширення колонок — покроковий порядок: де оголосити колонку, як підключити серверне сортування за нею, які перевірки прогнати. Розрахований на розробника, який бачить проєкт уперше.
- Документація інтеграції — контракти обміну з вашим API: формат запиту при зміні сторінки та фільтрів, структура відповіді, поведінка при порожньому результаті та помилці, пагінація курсором або сторінками.
- Інструкція для команди — як підняти проєкт локально, де лежать тестові дані, які команди проганяють перевірки та збірку, що дивитися при розходженні чисел у таблиці та у вивантаженні.
- Набір перевірок — тести на сортування, фільтрацію, пагінацію та вивантаження, включно з крайніми випадками: порожня відповідь, остання неповна сторінка, скидання фільтрів.
- Список відомих обмежень — чесний перелік того, що свідомо не увійшло в обсяг і які місця варто переглянути при зростанні даних.
Кожен артефакт прив'язаний до робочого коду, а не існує окремо від нього. Якщо через пів року колонок стане вдвічі більше, розширення йде за регламентом — без звернення до авторів початкової версії.
Чим серверна пагінація відрізняється від клієнтської на практиці
Клієнтська пагінація тримає весь набір рядків у пам'яті браузера: таблиця один раз забирає дані й далі ріже їх сама, миттєво перемикаючи сторінки без звернень до сервера. Поки рядків сотні-тисячі, це найпростіший і найшвидший шлях — сортування та фільтрація теж лягають на клієнт.
Проблема починається зі зростанням даних: кожен новий запис збільшує і обсяг вибірки, і час до першого рендеру, а навантаження лягає на пристрій користувача, а не на сервер.
Серверна пагінація перевертає модель: браузер запитує лише поточну сторінку, а фільтрацію, сортування та підрахунок загальної кількості рядків виконує база. Навантаження на сервер стає передбачуваним — на кожен перехід іде один компактний запит замість вивантаження всього масиву.
Саме тому при зростанні даних серверна модель залишається чутливою там, де клієнтська вже впирається в пам'ять і час відмальовування.
Вибір моделі — це питання про те, де живуть дані й як вони зростають. Клієнтська пагінація доречна для довідників, адмін-таблиць на кілька тисяч рядків і звітів, які рідко змінюються.
Серверна — для журналів подій, замовлень, логів і будь-яких наборів, які поповнюються постійно й вимірюються десятками тисяч рядків і більше.
На практиці моделі часто комбінують: сервер віддає сторінку, а сортування всередині неї та швидкий пошук по завантаженому шматку таблиця робить на клієнті. Так зберігається миттєва реакція на дії користувача і не зростає навантаження на сервер.
Ми розбираємо конкретний набір даних та його динаміку, після чого фіксуємо модель — інакше таблиця або гальмує на старті, або впирається в стелю при першому ж зростанні.
Кейс: таблиця на 80 тисяч рядків перестала зависати при фільтрації
Замовник прийшов із робочою таблицею складського обліку: 80 тисяч рядків, 14 колонок, фільтри за статусом, датами та контрагентом.
На кожному введенні символу в поле пошуку інтерфейс завмирав на 4-6 секунд — React перемальовував усі рядки одразу, а фільтрація йшла по повному масиву в пам'яті. Користувачі звикли «клікати й чекати», частину операцій проводили в Excel, бо там відгук був швидшим. Підтримка отримувала по 15-20 звернень на тиждень із формулюванням «таблиця не відповідає».
Ми переписали шар даних і рендеринг на TanStack Table. Логіку фільтрації та сортування винесли на серверну пагінацію, у браузері залишили лише віртуалізований список — у DOM живе 30-40 рядків замість 80 тисяч.
Стан фільтрів тримаємо в URL, щоб посилання на конкретну вибірку можна було надіслати колезі. Обсяг коду самої таблиці скоротився з ~2400 до ~900 рядків: пішла ручна синхронізація сортування, виділення рядків і пагінації, яку раніше підтримували вручну.
| Метрика | До | Після |
|---|---|---|
| Відгук на введення фільтра | 4-6 с | 120-200 мс |
| Зависання інтерфейсу | регулярно при фільтрації | не відтворюються |
| Рядків у DOM | 80 000 | 30-40 |
| Код таблиці | ~2400 рядків | ~900 рядків |
| Звернення в підтримку | 15-20 на тиждень | 1-2 на місяць |
Через місяць після викату команда замовника додала ще дві колонки та новий фільтр — без правок у ядрі таблиці, лише описом конфігурації. Це й був головний результат: розширювати таблицю стало дешевше, ніж підтримувати стару.
Часті технічні сумніви перед стартом робіт
Перед стартом майже кожна команда ставить один і той самий набір питань — вони стосуються не самої бібліотеки, а того, як вона уживеться з уже працюючим продуктом. Нижче — відповіді на п'ять сумнівів, які найчастіше виринають на технічних дзвінках.
Сумісність: чи спрацює з нашим поточним стеком?
TanStack Table — це headless-ядро: воно відповідає за сортування, фільтрацію, групування, пагінацію та віртуалізацію рядків, але не нав'язує розмітку та стилі.
Тому таблиця вбудовується в будь-який поточний інтерфейс — React, Vue, Svelte, Solid — і не конфліктує з вашою дизайн-системою. Ми підключаємо її до наявних джерел даних через ваш транспортний шар, без переписування бекенду.
Міграція: що буде зі старою таблицею та її даними?
Переносимо поступово: спочатку піднімаємо нову таблицю поруч зі старою на тому самому наборі даних, звіряємо вибірки, сортування та агрегати порядково. Тільки після того, як розбіжності дорівнюють нулю, перемикаємо трафік.
Стан фільтрів і колонок можна зберігати в URL або локальному сховищі — користувач не втрачає контекст при переходах.
Підтримка коду: хто супроводжуватиме після здачі?
Віддаємо репозиторій з читабельною структурою: конфігурація колонок, комірки та хуки винесені в окремі модулі, логіка не розмазана по компонентах. Пишемо документацію щодо розширення — як додати колонку, фільтр або джерело даних без правки ядра. Далі або супроводжуємо ми, або ваша команда веде самостійно.
Тестування: як переконатися, що таблиця не зламається на реальних даних?
Покриваємо перевірками критичні шляхи: сортування, фільтрацію, пагінацію, вибір рядків і граничні випадки — порожні набори, великі обсяги, биті значення. Прогоняємо на ваших реальних вивантаженнях, а не на синтетиці, щоб зловити аномалії до релізу.
Терміни впровадження: скільки це займе?
Першу робочу версію з базовими операціями показуємо рано — далі ітераціями нарощуємо фільтри, групування та віртуалізацію. Точний графік залежить від кількості колонок, джерел і правил доступу, тому фіксуємо етапи після розбору вашої задачі.
Опишіть поточну таблицю та вимоги — повернемося з оцінкою, планом міграції та складом перевірок.
Обговоримо ваше завдання та повернемося з оцінкою й планом
Перша розмова триває 30-40 хвилин і не вимагає від вас технічного завдання. Достатньо описати, яку задачу вирішують таблиці сьогодні: скільки рядків і колонок у реальних даних, хто і як часто їх фільтрує, що відбувається під час вивантаження.
Цього достатньо, щоб зрозуміти клас рішення — віртуалізація рядків, серверна пагінація, агрегати на стороні бази — і не проєктувати зайвого.
Окремо проговоримо підготовку даних: звідки надходять записи, у якому вигляді лежать зараз, чи є довідники та права доступу за ролями. Часто вузьке місце не в самій таблиці, а в тому, як влаштована вибірка на бекенді — це з'ясовується на першому ж розборі.
Після розмови ми надсилаємо оцінку робіт і план впровадження. До них входить:
- схема даних і джерела, з якими належить працювати;
- перелік сценаріїв: сортування, фільтри, групування, редагування, експорт;
- вимоги до серверної частини — пагінація, агрегати, кешування важких вибірок;
- етапи робіт із порядком постачання та точками, де ви бачите проміжний результат;
- склад команди та ролі на проєкті;
- ризики: обсяг даних, нестабільні джерела, обмеження поточного стеку;
- формат приймання — на яких даних і сценаріях перевіряємо результат.
Оцінка спирається на ваші реальні обсяги, а не на усереднені припущення, тому після неї план впровадження не переписується на середині.
Якщо частина даних ще не оцифрована або джерела не готові, це теж фіксуємо — або закладаємо підготовку окремим етапом, або пропонуємо рішення, яке працює на поточних вивантаженнях.
Опишіть задачу в зручному вигляді — посиланням на прототип, списком сценаріїв або прикладом таблиці, з якою працюєте зараз. Повернемося з оцінкою та планом впровадження, за яким можна ухвалювати рішення.







