Розробка фронтенду на React для 1С-Бітрікс
Використання React у зв'язці з 1С-Бітрікс викликає закономірне запитання: навіщо React, якщо є компоненти Бітрікс? Відповідь прагматична: коли вимоги до інтерактивності сторінок виходять за межі jQuery-віджетів, а команда фронтенду вже працює на React і TypeScript — тягнути старий стек Бітрікс не має сенсу.
Патерни інтеграції React з Бітрікс
Три основні сценарії використання React у Бітрікс-проєкті:
1. Вбудовані віджети. React-компонент монтується на конкретний DOM-елемент усередині Бітрікс-шаблону. Оптимально для складних форм, інтерактивних фільтрів, кастомних UI-компонентів.
2. Сторінка-SPA всередині Бітрікс. Весь контент сторінки рендериться React, Бітрікс слугує лише контейнером (шапка, футер, меню) і джерелом даних через API.
3. Повний headless. React-застосунок живе окремо, Бітрікс — тільки API. Найчистіший підхід, але потребує найбільших інвестицій.
Налаштування проєкту
Структура проєкту для React-фронтенду всередині Бітрікс:
/local/
/js/
/src/ # вихідники React
/components/
/hooks/
/api/ # шар роботи з Бітрікс API
bitrix.ts
catalog.ts
cart.ts
/store/ # Zustand/Redux
vite.config.ts
package.json
tsconfig.json
/templates/
/main/ # Бітрікс-шаблон сайту
Критично тримати React-вихідники в /local/js/src/, а не в public/ — так вони не потрапляють у веб-доступ напряму і обробляються через збирач.
Типізований клієнт Бітрікс API
Замість прямих fetch-запитів створіть типізований API-клієнт:
// /local/js/src/api/bitrix.ts
interface BitrixResponse<T> {
result: T;
total?: number;
error?: string;
}
class BitrixApiClient {
private baseUrl: string;
private sessionId: string;
constructor() {
this.baseUrl = '/local/ajax/api.php';
// Отримуємо sessid з глобальної змінної Бітрікс
this.sessionId = (window as any).BX?.bitrix_sessid?.() || '';
}
async get<T>(action: string, params: Record<string, unknown> = {}): Promise<T> {
const url = new URL(this.baseUrl, window.location.origin);
url.searchParams.set('action', action);
Object.entries(params).forEach(([k, v]) =>
url.searchParams.set(k, String(v)));
const response = await fetch(url.toString(), {
headers: { 'X-Bitrix-Csrf-Token': this.sessionId },
});
const data: BitrixResponse<T> = await response.json();
if (data.error) throw new Error(data.error);
return data.result;
}
async post<T>(action: string, body: Record<string, unknown>): Promise<T> {
const formData = new FormData();
formData.append('action', action);
formData.append('sessid', this.sessionId);
Object.entries(body).forEach(([k, v]) =>
formData.append(k, String(v)));
const response = await fetch(this.baseUrl, {
method: 'POST',
body: formData,
});
const data: BitrixResponse<T> = await response.json();
if (data.error) throw new Error(data.error);
return data.result;
}
}
export const bitrixApi = new BitrixApiClient();
React Query для роботи з даними
React Query (TanStack Query) — стандартний вибір для роботи із серверними даними в React. Інтеграція з Бітрікс:
// /local/js/src/api/catalog.ts
import { useQuery } from '@tanstack/react-query';
import { bitrixApi } from './bitrix';
interface CatalogItem {
id: number;
name: string;
price: number;
quantity: number;
previewPicture: string;
}
export function useCatalogItems(sectionId: number, page: number) {
return useQuery({
queryKey: ['catalog', sectionId, page],
queryFn: () => bitrixApi.get<CatalogItem[]>('catalog.list', {
section_id: sectionId,
page,
limit: 24,
}),
staleTime: 5 * 60 * 1000, // кеш на 5 хвилин
});
}
// У компоненті:
function CatalogSection({ sectionId }: { sectionId: number }) {
const [page, setPage] = useState(1);
const { data, isLoading, error } = useCatalogItems(sectionId, page);
if (isLoading) return <CatalogSkeleton />;
if (error) return <ErrorMessage error={error} />;
return (
<div className="catalog-grid">
{data?.map(item => <ProductCard key={item.id} item={item} />)}
<Pagination page={page} onChange={setPage} />
</div>
);
}
Інтеграція з авторизацією Бітрікс
Авторизація — специфічне завдання при React + Бітрікс. Стандартний підхід: Бітрікс керує сесією та авторизацією, React перевіряє поточний стан через API:
// Хук для перевірки авторизації
export function useAuth() {
return useQuery({
queryKey: ['auth'],
queryFn: () => bitrixApi.get<{ isAuthorized: boolean; userId?: number }>('user.current'),
staleTime: Infinity, // не перезапитувати без потреби
});
}
Для дій, що потребують авторизації (додавання до кошика, оформлення замовлення), при неавторизованому користувачі перенаправляйте на стандартну сторінку авторизації Бітрікс — не пишіть свою, якщо немає специфічних вимог.
Тестування
Компоненти тестуються через Vitest + Testing Library, незалежно від Бітрікс:
// Мокуємо API для тестів
vi.mock('../api/bitrix', () => ({
bitrixApi: {
get: vi.fn().mockResolvedValue([
{ id: 1, name: 'Товар 1', price: 1000 }
]),
}
}));
test('рендерить список товарів каталогу', async () => {
render(<CatalogSection sectionId={5} />);
expect(await screen.findByText('Товар 1')).toBeInTheDocument();
});
React-фронтенд у Бітрікс-проєкті працює добре, коли правила гри чіткі: Бітрікс відповідає за дані та бізнес-логіку, React — за UI та взаємодію. Змішувати логіку в шаблонах Бітрікс і React-компонентах одночасно — шлях до непідтримуваного коду через 6 місяців.







