Розробка фільтра товарів на React для 1С-Бітрікс
Штатний компонент bitrix:catalog.smart.filter працює через server-side рендеринг із повним перезавантаженням сторінки або AJAX-заміною HTML. При кожній зміні фільтра — HTTP-запит, серверний рендеринг, заміна блоку в DOM. На каталозі в 50 000 SKU з 30+ характеристиками час відповіді становить 800–2000 мс, і це ще без урахування часу рендерингу на фронті.
React-фільтр змінює підхід: UI оновлюється миттєво, запит до сервера надсилається з debounce 300–500 мс, результати оновлюються у фоні. Користувач бачить відгук одразу, а не чекає round-trip до сервера.
Архітектура React-фільтра
Фільтр складається з трьох незалежних частин: компонент фільтра (чекбокси, ренджі, сортування), компонент каталогу (список товарів, пагінація), URL-синхронізація (стан фільтра відображається в URL для шерингу і SEO).
Стан фільтра синхронізується з URL через useSearchParams з React Router або нативний URLSearchParams. Це критично: користувач має мати можливість скопіювати URL із застосованими фільтрами.
// Хук синхронізації фільтра з URL
function useFilterState(initialFilters: FilterState) {
const [searchParams, setSearchParams] = useSearchParams();
const filters = useMemo(() => {
return parseFiltersFromParams(searchParams, initialFilters);
}, [searchParams]);
const setFilters = useCallback((newFilters: Partial<FilterState>) => {
const params = buildParamsFromFilters({ ...filters, ...newFilters });
setSearchParams(params, { replace: true }); // replace, не push — не засмічуємо історію
}, [filters, setSearchParams]);
return [filters, setFilters] as const;
}
API на стороні Бітрікс
Серверний endpoint приймає параметри фільтра і повертає товари + фасетні лічильники (скільки товарів за кожним значенням характеристики).
public function getProductsAction(array $filter = [], int $page = 1): array
{
// Будуємо Бітрікс-фільтр з параметрів запиту
$bxFilter = $this->buildBitrixFilter($filter);
// Товари
$result = \CIBlockElement::GetList(
['SORT' => 'ASC'],
$bxFilter,
false,
['nPageSize' => 24, 'iNumPage' => $page],
['ID', 'NAME', 'PREVIEW_PICTURE', 'DETAIL_PAGE_URL',
'CATALOG_PRICE_1', 'PROPERTY_BRAND', 'PROPERTY_COLOR']
);
$products = [];
while ($product = $result->GetNextElement()) {
$fields = $product->GetFields();
$props = $product->GetProperties();
$products[] = $this->formatProduct($fields, $props);
}
// Фасетні лічильники для оновлення варіантів фільтра
$facets = $this->getFacets($bxFilter, $filter);
return [
'products' => $products,
'total' => $result->SelectedRowsCount(),
'facets' => $facets,
];
}
Для фасетних лічильників використовується \Bitrix\Iblock\Component\Tools або прямі запити до таблиць b_iblock_element_property з GROUP BY — залежить від навантаження та обсягу каталогу.
Типи фільтрів та їх реалізація
Чекбокс-групи (бренд, колір, матеріал) — найпоширеніший тип. Значення приходять з властивостей інфоблоку. На фронті — список з пошуком усередині групи при великій кількості значень (20+).
Діапазон ціни — ціновий слайдер із двома повзунками. Бібліотека rc-slider або нативна реалізація на CSS custom properties. Запит надсилається з debounce 500 мс — інакше кожен піксель руху слайдера тригерить запит.
Рейтинг — зірковий рейтинг як фільтр (від N зірок).
Розмірна сітка — кнопки-перемикачі. Особливість: доступність конкретного розміру залежить від залишків, тому неактивні значення мають підсвічуватись сірим, а не просто бути відсутніми.
Кейс: фільтр для маркетплейсу одягу
Мультивендорний каталог, ~180 000 SKU, 45 характеристик. Завдання: фільтр має працювати миттєво, підтримувати багаторівневі залежності (вибір категорії змінює доступні фільтри) і відображати стан у URL для SEO.
Штатний SmartFilter Бітрікс давав час відповіді 1.4–2.1 сек, при цьому фасетні лічильники перераховувались при кожному запиті і ставали вузьким місцем.
Рішення:
-
Фасети винесено в окремий кешований endpoint. Лічильники перераховуються через чергу (
\Bitrix\Main\Application::getInstance()->addBackgroundJob()) після зміни залишків, а не в реальному часі на кожен запит. -
На фронті — optimistic UI: чекбокс відмічається миттєво, лічильник товарів оновлюється з невеликою затримкою. Користувач не чекає підтвердження від сервера для візуального відгуку.
-
Мобільна версія фільтра — окремий компонент з bottom sheet (виїжджає знизу). Десктоп — сайдбар. Переключення через CSS media query + React context.
-
Порожні результати — не білий екран, а блок з пропозицією розширити фільтр (прибрати одну з характеристик). React аналізує, який останній вибраний параметр дає 0 результатів, і пропонує його прибрати.
| Характеристика | SmartFilter | React-фільтр |
|---|---|---|
| Час відгуку на чекбокс | 1400–2100 мс | 0 мс (UI), 280–400 мс (дані) |
| Оновлення лічильників | При кожному запиті | З кешу, оновлення фоном |
| Глибина лінк-шерингу | Часткова | Повна (всі параметри в URL) |
| Мобільний UX | Окрема сторінка | Bottom sheet без переходу |
SEO і SSR
Фільтр на React створює SEO-проблему: пошуковик не завжди виконує JavaScript. Рішень кілька.
SSR через окремий рендерер — важко, потребує Node.js-інфраструктури поряд із Бітрікс.
Prerendering — SPA рендериться через headless Chrome при краулінгу. Реалізується через Prerender.io або nginx-конфіг, який визначає User-Agent бота і проксує запит на рендерер.
Гібридний підхід (рекомендований): сторінки з SEO-цінними фільтрами (категорія + бренд) мають статичні PHP-URL, які рендерить Бітрікс. React-фільтр працює поверх цих сторінок, але початковий стан бере з PHP-шаблону (переданий у window.__INITIAL_STATE__). Боти бачать HTML, користувачі — інтерактивний React.
Оптимізація продуктивності
Нескінченна прокрутка vs. пагінація: для мобільних — infinite scroll через IntersectionObserver, для десктопу — пагінація (SEO + можливість повернутися до конкретної сторінки).
Віртуалізація списку при великій кількості результатів (react-virtual або @tanstack/react-virtual) — при відображенні 200+ карток без віртуалізації DOM стає важким.
React Query для кешування: перехід між сторінками каталогу не робить повторний запит, якщо дані в кеші свіжі (staleTime: 30_000).
Склад робіт
- Аналіз структури каталогу: характеристики, типи фільтрів, обсяг даних
- API-контролер: фільтрація, пагінація, фасети, кешування
- Розробка React: компоненти фільтра, каталогу, синхронізація з URL
- SEO-стратегія: prerendering або гібридний підхід
- Тестування продуктивності під навантаженням
Терміни: базовий фільтр (чекбокси + діапазон ціни) — 2–3 тижні. Повнофункціональний з фасетами, мобільним UX і SEO-стратегією — 5–8 тижнів.







