Angular IDPStrong Junior
Модулі / Грид / Клієнт чи сервер
🔥 0

Модуль 5 · урок 4 з 10

Клієнт чи сервер

Фільтрувати, сортувати й гортати можна на клієнті або на сервері. У таблиці ліда прямо написано «client-side pagination», тож у практиці робимо клієнтську — але розуміти межу треба, бо на роботі майже завжди буде навпаки.

Дві моделі

КЛІЄНТСЬКА сервер 1 запит усі 800 рядків у памʼяті фільтр · сорт · зріз зміна фільтра — миттєва, без мережі СЕРВЕРНА сервер запит на кожну зміну стану 25 рядків + total лише поточна сторінка
Клієнтська модель обмінює трафік на швидкість реакції, серверна — навпаки. Вибір визначає обсяг даних.

Де межа

КлієнтськаСерверна
Скільки рядківДо кількох тисячВід десятків тисяч
Реакція на фільтрМиттєваЗатримка мережі
Перший запитВажкийЛегкий
Складність фронтендуУся логіка в тебеМінімальна
Складність бекендуМінімальнаУся логіка там
Актуальність данихЗастарівають після завантаженняЗавжди свіжі

Практичний орієнтир: якщо весь набір даних важить менше умовного мегабайта й не змінюється щосекунди — бери клієнтську. Вона дає різко кращий досвід: фільтри реагують без затримки, сортування миттєве, і не треба лікувати гонки запитів.

Клієнтська: одна чиста функція

export function applyState<T>(rows: readonly T[], state: TableState): Page<T> {
  let out = rows;

  // 1. пошук
  if (state.query) {
    const q = normalize(state.query);
    out = out.filter(r => matches(r, q));
  }

  // 2. фільтри по колонках
  for (const [key, value] of Object.entries(state.filters)) {
    if (value) out = out.filter(r => String(r[key as keyof T]) === value);
  }

  // 3. сортування
  if (state.sort.length) {
    out = [...out].sort(compareBy(state.sort));   // копія: sort мутує
  }

  // 4. зріз сторінки — ОБОВʼЯЗКОВО останнім
  const total = out.length;
  const start = (state.page - 1) * state.size;

  return { items: out.slice(start, start + state.size), total };
}
Порядок операцій не довільний

Фільтрувати → сортувати → різати. Якщо порізати раніше, відсортуєш лише поточну сторінку, а total покаже кількість усіх рядків, а не знайдених. Це два різні баги, які часто зустрічаються разом.

Головна перевага такого підходу — applyState це чиста функція. Її можна протестувати без Angular взагалі, і в модулі 8 це буде один із найпростіших тестів.

Серверна: та сама функція, тільки в моці

// мок із модуля 4 просто виконує applyState у себе всередині
list(state: TableState): Observable<Page<Task>> {
  return this.simulate(() => applyState(this.tasks, state));
}

Ось чому мок-шар із контрактом був вартий зусиль: перехід на серверну модель — це перенесення однієї функції з фронтенду на бекенд. Компоненти й стор не змінюються взагалі, змінюється тільки те, хто виконує applyState.

Гібрид, який часто зустрічається

// пагінація й фільтри на сервері, сортування поточної сторінки на клієнті
// ⚠️ так робити не варто: користувач сортує лише 25 видимих рядків,
// а думає, що сортує весь набір

Це класична пастка напівмір. Якщо пагінація серверна, то сортування й фільтрація теж мають бути серверними — інакше інтерфейс бреше. Змішувати можна лише свідомо й із поясненням користувачу.