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 Appointment Booking Widget for a Medical Center
    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 разработка для 1С-Битрикс и когда она нужна

Каталог на 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/ или кастомные эндпоинты через CRestServer. Максимум контроля, но и максимум работы.

  • Клиентский роутинг через 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

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

Как React улучшает Core Web Vitals

  • 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%

Проекты, сроки и что входит в работу

Типичные проекты, которые мы уже сделали

  • Интернет-магазин на 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 на проекте

  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.

Почему React, а не Vue или шаблоны Битрикса

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

1С-Битрикс + React — это не теоретическая архитектура, а рабочая связка, которая уже обслуживает каталоги с десятками тысяч SKU и B2B-кабинеты с тяжёлой бизнес-логикой. Подробнее о React и 1С-Битрикс. Получите консультацию — пришлём вам кейсы, похожие на ваш проект. Свяжитесь с нами, чтобы обсудить детали. Реализуем под ключ с гарантией результата.