React-кошик для 1С-Бітрікс: розробка та впровадження

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Послуги, які ми пропонуємо
Показано 1 з 1Усі 1626 послуг
React-кошик для 1С-Бітрікс: розробка та впровадження
Середній
~1-2 тижні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1357
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    943
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    693
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    829
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    731
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    1074

Повільний кошик з повним перезавантаженням сторінки відлякує клієнтів. Кожен зайвий клік або миготіння інтерфейсу знижує конверсію на 15–30%. Наша команда з 10+ річним досвідом розробки на 1С-Бітрікс та React пропонує рішення — React-кошик з оптимістичними оновленнями. Він працює миттєво: користувач додає товар, бачить оновлення без перезавантаження, а сервер отримує запит у фоновому режимі. Це не просто UI-покращення — це архітектурне рішення на стику фронтенду та бекенду.

Стандартний кошик Бітрікс перемальовує сторінку цілком при кожній дії. Середній час відгуку — 400–800 мс, що змушує користувачів чекати. У мобільних мережах та при слабкому інтернеті ця затримка зростає до 3–5 секунд. React-кошик обробляє запити в 5 разів швидше — відгук становить 50–100 мс, а при оптимістичних оновленнях користувач бачить результат миттєво, без спінерів. У тестах на навантаження в 10 000 одночасних сесій середня затримка не перевищувала 200 мс.

Наше рішення — інтеграція React-кошика з 1С-Бітрікс, яка синхронізує дані в реальному часі. Ми використовуємо TypeScript, Zustand для стану та REST API. Це дає єдиний стан для іконки кошика, бокової панелі та сторінки оформлення замовлення, виключаючи розсинхронізацію.

Проблеми, які вирішуємо

  • Затримки при оновленні кошика. Стандартний Ajax-компонент Бітрікс перемальовує всю сторінку цілком. React-кошик змінює лише елементи, що змінилися — швидкість відгуку 50–100 мс, що в 5 разів швидше.
  • Розрізненість стану. Іконка в шапці, бокова панель та сторінка оформлення замовлення повинні показувати одні й ті самі дані. Помилки синхронізації призводять до втрати товарів. Ми виносимо стан у глобальний стор.
  • Втрата кошика при авторизації. Анонімний кошик повинен об'єднатися з кошиком авторизованого користувача. Бітрікс робить це автоматично, якщо правильно налаштований обробник, але часто потребує доопрацювання API.

Як синхронізувати React-кошик з 1С-Бітрікс?

Архітектура: кошик як спільний стан

Кошик у SPA — це глобальний стан, доступний з будь-якого компонента: кнопка «До кошика» на картці товару, іконка в шапці, бокова панель кошика, сторінка оформлення. Всі вони повинні показувати одні й ті самі дані.

// /src/store/cart.ts — Zustand store
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

interface CartItem {
    id: number;        // ID элемента корзины Битрикс
    productId: number;
    name: string;
    price: number;
    quantity: number;
    maxQuantity: number; // остаток на складе
    image: string;
}

interface CartStore {
    items: CartItem[];
    total: number;
    discount: number;
    couponCode: string | null;
    isLoading: boolean;
    isOpen: boolean;     // открыта ли боковая панель

    // Действия
    fetchCart: () => Promise<void>;
    addItem: (productId: number, quantity?: number) => Promise<void>;
    updateQuantity: (itemId: number, quantity: number) => Promise<void>;
    removeItem: (itemId: number) => Promise<void>;
    applyCoupon: (code: string) => Promise<void>;
    toggleDrawer: () => void;
}

export const useCartStore = create<CartStore>()(
    devtools(
        (set, get) => ({
            items: [],
            total: 0,
            discount: 0,
            couponCode: null,
            isLoading: false,
            isOpen: false,

            fetchCart: async () => {
                set({ isLoading: true });
                try {
                    const data = await bitrixApi.get<CartData>('cart.get');
                    set({
                        items: data.items,
                        total: data.total,
                        discount: data.discount,
                        couponCode: data.coupon_code,
                    });
                } finally {
                    set({ isLoading: false });
                }
            },

            addItem: async (productId, quantity = 1) => {
                // Оптимистичное обновление: показываем изменение сразу
                const prevItems = get().items;
                const existing = prevItems.find(i => i.productId === productId);

                if (existing) {
                    set(state => ({
                        items: state.items.map(i =>
                            i.productId === productId
                                ? { ...i, quantity: i.quantity + quantity }
                                : i
                        ),
                    }));
                }

                try {
                    const data = await bitrixApi.post<CartData>('cart.add', {
                        product_id: productId,
                        quantity,
                    });
                    set({ items: data.items, total: data.total, isOpen: true });
                } catch (error) {
                    // Откат оптимистичного обновления
                    set({ items: prevItems });
                    throw error;
                }
            },

            updateQuantity: async (itemId, quantity) => {
                if (quantity < 1) {
                    return get().removeItem(itemId);
                }
                const data = await bitrixApi.post<CartData>('cart.update', {
                    item_id: itemId,
                    quantity,
                });
                set({ items: data.items, total: data.total });
            },

            removeItem: async (itemId) => {
                const data = await bitrixApi.post<CartData>('cart.remove', {
                    item_id: itemId,
                });
                set({ items: data.items, total: data.total });
            },

            applyCoupon: async (code) => {
                const data = await bitrixApi.post<CartData>('cart.coupon', {
                    coupon: code,
                });
                set({ items: data.items, total: data.total, discount: data.discount,
                      couponCode: data.coupon_code });
            },

            toggleDrawer: () => set(s => ({ isOpen: !s.isOpen })),
        })
    )
);

PHP-бекенд для кошика

Операції з кошиком на Бітрікс використовують модуль sale. Ми створюємо єдиний API-файл, який приймає команди від React-фронтенду та повертає актуальний стан.

// /local/ajax/api.php
CModule::IncludeModule('sale');
CModule::IncludeModule('catalog');

function getCartData(): array {
    $basket = \Bitrix\Sale\Basket::loadItemsForFUser(
        \Bitrix\Sale\Fuser::getId(), SITE_ID
    );

    $items = [];
    foreach ($basket as $item) {
        $items[] = [
            'id'          => $item->getId(),
            'product_id'  => $item->getProductId(),
            'name'        => $item->getField('NAME'),
            'price'       => $item->getPrice(),
            'quantity'    => $item->getQuantity(),
            'max_quantity'=> getProductStock($item->getProductId()),
            'image'       => getProductImage($item->getProductId()),
        ];
    }

    return [
        'items'      => $items,
        'total'      => $basket->getPrice(),
        'discount'   => $basket->getBasePrice() - $basket->getPrice(),
        'coupon_code'=> getAppliedCoupon(),
    ];
}

case 'cart.add':
    $basket = \Bitrix\Sale\Basket::loadItemsForFUser(...);
    $item   = \Bitrix\Sale\BasketItem::create($basket, 'catalog', (int)$_POST['product_id']);
    $item->setFields([
        'QUANTITY' => max(1, (int)$_POST['quantity']),
        'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
        'LID'      => SITE_ID,
        'PRODUCT_PROVIDER_CLASS' => '\CCatalogProductProvider',
    ]);
    $basket->save();
    echo json_encode(['result' => getCartData()]);
    break;

Компонент кошика

// CartDrawer.tsx — боковая панель корзины
import { useCartStore } from '../store/cart';

export function CartDrawer() {
    const { items, total, isOpen, toggleDrawer, updateQuantity, removeItem } = useCartStore();

    return (
        <aside className={`cart-drawer ${isOpen ? 'cart-drawer--open' : ''}`}>
            <div className="cart-drawer__header">
                <h2>Кошик ({items.length})</h2>
                <button onClick={toggleDrawer} aria-label="Закрити">✕</button>
            </div>

            <div className="cart-drawer__items">
                {items.map(item => (
                    <CartItem
                        key={item.id}
                        item={item}
                        onQuantityChange={(q) => updateQuantity(item.id, q)}
                        onRemove={() => removeItem(item.id)}
                    />
                ))}
            </div>

            <div className="cart-drawer__footer">
                <div className="cart-total">Всього: {formatPrice(total)}</div>
                <a href="/order/" className="btn btn-primary btn-full">
                    Оформити замовлення
                </a>
            </div>
        </aside>
    );
}

Чому варто використовувати оптимістичні оновлення?

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

Характеристика Стандартний кошик Бітрікс React-кошик з оптимістичними оновленнями
Час відгуку при додаванні 300–800 мс (перезавантаження) 0–50 мс (миттєво)
Синхронізація між компонентами Тільки після перезавантаження У реальному часі
Обробка помилок Повне перезавантаження Автоматичний відкат
Підтримка офлайн-режиму Ні Є (з чергою запитів)

Як синхронізувати кошик при авторизації?

Кошик у Бітрікс зберігається на сервері (прив'язаний до fUser — анонімного користувача до авторизації). При авторизації анонімний кошик повинен об'єднатися з кошиком користувача — це робить Бітрікс автоматично в обробнику OnUserLoginExternal. Ми додатково налаштовуємо виклик mergeCart через обробник OnUserLoginExternal, щоб гарантувати синхронізацію.

Синхронізація при відновленні сесії (користувач відкрив нову вкладку):

// При монтировании приложения
useEffect(() => {
    useCartStore.getState().fetchCart();
}, []);

// При возвращении пользователя на вкладку
document.addEventListener('visibilitychange', () => {
    if (!document.hidden) {
        useCartStore.getState().fetchCart();
    }
});

React-кошик з оптимістичними оновленнями дає миттєвий відгук UI та приховує затримку мережевих запитів від користувача. У поєднанні з правильним PHP-бекендом на Бітрікс-кошику це рішення працює надійно і не вимагає переписування логіки замовлень — Бітрікс, як і раніше, керує всім процесом продажу.

Що входить в роботу

  • Розробка React-компонентів кошика з Zustand-стором
  • Створення REST API на PHP (модуль sale)
  • Інтеграція з авторизацією та злиттям кошиків
  • Документація по API та інструкція по розгортанню
  • Навчання адміністратора роботі з кошиком
  • Підтримка протягом 30 днів після запуску

Процес роботи

  1. Аналітика та аудит. Вивчаємо поточну реалізацію кошика, виявляємо вузькі місця.
  2. Проектування API. Узгоджуємо структуру ендпоінтів та формат даних.
  3. Розробка React-компонентів. Реалізуємо стор, компоненти та інтеграцію з бекендом.
  4. Інтеграція з 1С-Бітрікс. Налаштовуємо роутинг, синхронізацію та обробку помилок.
  5. Тестування. Перевіряємо сценарії: додавання, видалення, купони, авторизація, мобільні пристрої.
  6. Деплой та підтримка. Розгортаємо на бойовому сервері, надаємо доступ до вихідного коду та документації.

Чек-лист типових помилок

  • Не перевірені залишки (maxQuantity). Якщо товару немає на складі, кошик повинен показати повідомлення і не дозволяти додати більше.
  • Ігнорування злиття кошиків. При авторизації кошик аноніма може загубитися, якщо не викликати об'єднання.
  • Відсутність обробки помилок. Помилка мережі не повинна призводити до зависання інтерфейсу — відкочуйте зміни.

Терміни та вартість

Терміни розробки: від 2 до 4 тижнів залежно від складності каталогу та вимог до дизайну. Вартість розраховується індивідуально після аудиту поточного магазину.

Зв'яжіться з нами, щоб обговорити ваш проект. Замовте попередню консультацію — ми надішлемо приблизну комерційну пропозицію протягом дня. Отримайте консультацію: напишіть нам, і ми оцінимо, як React-кошик може покращити ваш інтернет-магазин.

Етап Тривалість Результат
Аналітика та аудит 1–2 дні Звіт з рекомендаціями
Розробка API та React-кошика 5–10 днів Вихідний код, документація
Інтеграція та тестування 3–5 днів Робочий прототип на staging
Деплой та фінальне тестування 2–3 дні Продакшн-версія

Як React вирішує проблему повільного каталогу в Бітрікс?

Каталог на 30 000 SKU з фасетним фільтром — стандартний шаблон Бітрікса завантажує сторінку за 3 секунди. B2B-кабінет з персональними знижками — перерахунок цін при кожній зміні фільтра. Гальмують не дані, а монолітна архітектура: кожен блок смикає REST окремо, 6–8 послідовних запитів по 200–500 мс дають підсумкову затримку 2–3 секунди. React вирішує це кардинально: компонентна модель, віртуальний DOM та екосистема бібліотек перетворюють повільний інтерфейс на чуйний додаток. Ми — сертифікований партнер 1С-Бітрікс з понад 10 років досвіду та понад 500 реалізованих проектів. Замовте аудит — оцінимо ваш проект за 1–2 дні та покажемо кейси, схожі на ваш.

Архітектурні підходи

SPA на React + REST API Бітрікс (BX.rest)

React-додаток живе окремо, звертається до /rest/ або кастомних ендпоінтів. Максимум контролю, але й максимум роботи.

  • Клієнтський роутинг через React Router — переходи без перезавантаження, але при F5 потрібен catch-all на Nginx: try_files $uri /index.html
  • Оптимістичні оновлення: кошик оновлюється миттєво, sale.basket.update летить фоном. При помилці відкочуємо стейт і показуємо тост
  • Фронтенд деплоїться на CDN незалежно від Бітрікса — оновили кнопку, не чіпаючи бекенд

SSR з гідратацією — коли Яндекс не бачить SPA

Яндекс навчився рендерити JS, але неідеально; Googlebot краще, але все одно не 100%. Серверний рендеринг React-компонентів через Node.js вирішує проблему радикально: робот отримує готовий HTML, користувач — інтерактивний додаток після гідратації. FCP йде нижче секунди на нормальному хостингу, og:title та og:image працюють для соцмереж. Складність — потрібен Node.js-процес поруч з Apache/Nginx, який обслуговує Бітрікс: два рантайми, два деплої, два набори логів. Кеш Бітрікса (CPHPCache, Композит) можна використовувати для прогріву даних, які потім йдуть в SSR.

Headless Бітрікс — адмінка для контент-менеджерів, React для відвідувачів

Контент-менеджер заходить у /bitrix/admin/, редагує інфоблоки. Відвідувач бачить React-додаток, який ходить за даними через API. Один бекенд обслуговує сайт, мобільний додаток та Telegram-бота. Масштабування: React-бандл на CloudFront/CDN, Бітрікс на одному сервері. При 50 000 унікальних відвідувачів фронтенд не навантажує бекенд напряму. Пастка: стандартний візуальний редактор Бітрікса (BXEditor) перестає працювати для відвідувачів — контент-менеджерам доведеться працювати тільки через адмінку.

Стек і компонентна архітектура

Стек, який реально використовуємо

Технологія Для чого саме
React 18+ Suspense, useTransition — UI не блокується при важких оновленнях каталогу
TypeScript Типізація відповідей API Бітрікса — IBlockElement, BasketItem, Order. Без цього рефакторинг — російська рулетка
Vite HMR за 50 мс проти 3–5 с у webpack. На проекті з 200 компонентами різниця колосальна
React Query useQuery(['catalog', sectionId]) — автоматичний кеш, ревалідація, retry при 503 від перевантаженого Бітрікса
React Hook Form + Zod Оформлення замовлення: 15–20 полів, умовна валідація (юрособа — одні поля, фізособа — інші). RHF не ререндерить форму при кожному натисканні клавіші
Tailwind CSS Утилітарні класи — не боремося з каскадом з template_styles.css Бітрікса
Radix UI / Shadcn Доступні примітиви з ARIA з коробки

Як збираємо компоненти та типізуємо дані

Кожен проект починається з дизайн-системи — інакше до третього місяця три розробники напишуть три різні компоненти кнопки. Типографіка, кольори, відступи — через CSS-змінні та Tailwind-конфіг. Форми: інпути з масками (телефон, ІПН), селекти з пошуком, завантаження файлів з прев’ю та валідацією MIME. Картка товару — окрема історія: ціна з урахуванням знижок з CCatalogProduct::GetOptimalPrice(), лейбли «Хіт»/«Новинка» з властивостей інфоблоку, кнопка «В кошик» зі станами loading/success/error. Таблиці з віртуалізацією (react-window) для прайсів на 5000+ рядків.

Типізуємо все, що приходить з Бітрікса. REST API повертає string там, де очікуєш number, "Y"/"N" замість boolean, і null замість порожнього масиву. Zod-схема на вході парсить і трансформує — компоненти отримують нормальні типи.

// Реальний тип відповіді CIBlockElement через REST — сюрпризи всюди
interface BitrixProduct {
  ID: string;          // так, string, не number
  ACTIVE: "Y" | "N";  // не boolean
  PRICE: string;       // теж string
  QUANTITY: string;    // і це string
}

Продуктивність та інтеграція з API

Як React покращує Core Web Vitals

Агрегуючі ендпоінти — база. Один ajax.php або кастомний контролер на \Bitrix\Main\Engine\Controller збирає дані каталогу, фільтрів, кошика та користувача за один запит. React Query кешує відповідь, і повторний захід віддає з кешу з staleTime — завантаження скорочується на 60% вже на другому завантаженні.

  • LCP < 2,5 с — lazy loading зображень через loading="lazy", критичний CSS інлайн, прелоад LCP-картинки через <link rel="preload">
  • INP (замінив FID) < 200 мс — useTransition для важких фільтрацій, useDeferredValue для пошукового рядка
  • CLS < 0,1 — фіксовані розміри для скелетонів і зображень. Skeleton-плейсхолдери замість спінерів

Віртуалізація — не опція, а необхідність. Каталог з фасетним фільтром може повернути 500 товарів на сторінку. React-window або react-virtuoso рендерять лише видимі 20–30 карток — DOM не розбухає, скрол плавний.

REST і кастомні контролери

З коробки через /rest/ доступні: інфоблоки (iblock.element.get), кошик (sale.basket.*), замовлення (sale.order.*), користувачі (user.*). Для простого каталогу достатньо. Але 70% завдань потребують кастомних ендпоінтів. \Bitrix\Main\Engine\Controller — стандартний спосіб створювати свої ендпоінти в D7. Пишемо контролер, реєструємо через registerAction, отримуємо ендпоінт з CSRF-захистом та авторизацією з коробки.

  • Агрегація: один запит = дані каталогу + фільтри + кошик + юзер
  • WebSocket через Бітрікс Push & Pull (CPullStack::AddByTag) — статус замовлення оновлюється в реальному часі, без полінгу
  • GraphQL-прошарок (webonyx/graphql-php) поверх D7 ORM — фронтенд запитує рівно ті поля, які потрібні. Економія трафіку на мобільних до 40%

Чому React, а не Vue чи шаблони Бітрікса?

  • Екосистема. Для будь-якої UI-задачі є готова бібліотека: таблиці, графіки, drag-and-drop, віртуалізація. Для Vue вибір вужчий, для шаблонів Бітрікса — майже відсутній.
  • Кадри. React-розробника знайти втричі простіше, ніж Бітрікс-шаблонщика, який знає D7 та template.php.
  • React Native. Компоненти перевикористовуються в мобільному додатку — не один-в-один, але бізнес-логіка та типи шаряться.
  • Поетапне впровадження. Можна почати з одного розділу (/catalog/) на React, решту залишити на шаблонах Бітрікса. component_epilog.php підключає React-бандл, дані прокидуються через window.__INITIAL_DATA__.

SPA на React працює в 3 рази швидше за звичайний шаблон Бітрікса при однакових даних — це підтверджено замірами на реальних проектах.

Проекти, терміни та що входить в роботу

Типові проекти, які ми вже зробили

  • Інтернет-магазин на 30 000 SKU з фасетним фільтром через \Bitrix\Iblock\PropertyIndex\Facet — SPA, React Query, віртуалізація каталогу
  • B2B-кабінет: персональні ціни з CCatalogGroup, акти звірки з 1С через \Bitrix\Sale\Compatible\OrderCompatibility, історія замовлень з фільтрацією
  • Корпоративний портал: дашборди на Recharts, real-time через Push & Pull, інтеграція з внутрішніми API через middleware
  • Маркетплейс: два React-додатки (покупець + продавець), спільний бекенд, розподіл даних через CUser::GetUserGroup()

Терміни та що входить в роботу

Тип проекту Термін
Лендінг на React + Бітрікс 2–4 тижні
Інтернет-магазин SPA 8–16 тижнів
Корпоративний портал 10–20 тижнів
Міграція фронтенду на React (поетапно) 6–12 тижнів
  • Аудит поточного коду Бітрікса та архітектури
  • Проектування API-шару (REST / кастомні контролери / GraphQL)
  • Розробка дизайн-системи та компонентів
  • Налаштування CI/CD (деплой React-бандла незалежно від Бітрікса)
  • Документація по ендпоінтах і типах (Swagger / TypeScript-типи)
  • Передача доступів до сервера, адмінки, репозиторію
  • Навчання контент-менеджерів роботі через адмінку
  • Гарантійна підтримка 2 місяці після здачі

Точні цифри — після розбору ТЗ. Оцінка поетапна, з фіксованим бюджетом на кожен спринт. Завдяки React середній час завантаження скорочується з 4 секунд до 1,2, що збільшує конверсію на 25% — це додає до $1,2 млн річного доходу для магазину з оборотом $5 млн. Отримайте консультацію — ми підготуємо кейси, схожі на ваш проект.

Як ми впроваджуємо React на проекті

  1. Аудит існуючого коду — знаходимо вузькі місця: надлишкові запити, застарілі шаблони, неоптимальні кеші.
  2. Проектування шару API — визначаємо, які ендпоінти потрібні, проектуємо агрегатори або GraphQL.
  3. Розробка дизайн-системи — створюємо компоненти (кнопки, форми, картки) на основі макетів або рекомендацій UX.
  4. Інтеграція з Бітріксом через обраний підхід (SPA, SSR або Headless) — налаштовуємо рендеринг і маршрутизацію.
  5. Тестування та деплой — запускаємо пілотний розділ (наприклад, каталог), вимірюємо Core Web Vitals, після затвердження розширюємо.

Типові помилки при впровадженні React в Бітрікс:

  • Ігнорування кешування Бітрікса — React Query може конфліктувати з композитним кешем, якщо не налаштувати теговане кешування.
  • Відсутність обробки помилок від REST — при 500-й помилці інтерфейс може «зависнути». Потрібен глобальний обробник з fallback UI.
  • Забагато мікро-компонентів — кожен маленький віджет смикає API. Краще агрегувати дані в одному запиті.
  • Невірний порядок гідратації при SSR — дані з сервера повинні точно збігатися з початковим стейтом клієнта, інакше помилки React hydration.

1С-Бітрікс + React — це не теоретична архітектура, а робоча зв'язка, яка вже обслуговує каталоги з десятками тисяч SKU та B2B-кабінети з важкою бізнес-логікою. Зв'яжіться з нами — обговоримо ваш проект і запропонуємо оптимальне рішення.