React или сайт без фреймворка: когда React оправдан

Когда сайту нужен React, а когда фреймворк только добавляет вес: замер размера сборки, сравнение трёх подходов, что браузер умеет сам, островки, одни и те же задачи двумя способами и частые ошибки.

Стек и технологии Обновлено

Коротко

React оправдан, когда интерфейс работает как приложение: много состояний на одном экране, живые данные, сложные формы и редакторы — личные кабинеты, дашборды, SaaS, Mini Apps. Для сайтов, задача которых — показать содержание и привести к заявке, — корпоративных сайтов, лендингов, каталогов, блогов — фреймворк в основном добавляет вес: минимальное приложение на React — около 66 КБ сжатого JavaScript ещё до вашего кода, а браузер сегодня сам умеет модальные окна, всплывающие подсказки, проверку форм и переходы между страницами. Часто лучшее — сочетание: страницы — это серверный HTML, а React живёт только в тех блоках, где он действительно нужен.

Коротко: когда React, а когда без него

Задайте один вопрос: живёт ли экран после загрузки? Если человек в основном читает, сравнивает и заполняет форму — страница должна приходить готовой с сервера, а немного JavaScript добавит остальное. Если человек часами работает внутри экрана — фильтрует, перетаскивает, редактирует, получает живые обновления, — состояний становится много, и React держит их под контролем.

Ошибка — выбирать по привычке: лендинг на React, потому что «все так делают», или сложный дашборд на разрозненных скриптах, потому что «фреймворк тяжёлый». Обе ошибки стоят денег — первая скоростью и поиском, вторая ошибками и временем разработки.

  • Экран читают — серверный HTML
  • В экране работают — React
  • Часто — оба на одном сайте

Сколько весит React: замер

Одна и та же кнопка со счётчиком, собранная Vite 8 в рабочем режиме. React 19.3, размеры файла JavaScript.

React, после сжатия кода
214 КБ
React, gzip при передаче
66 КБ — ещё до вашего собственного кода
Чистый JavaScript, после сжатия
0,8 КБ
Чистый JavaScript, gzip
0,5 КБ
Что это значит
На быстром интернете разница невелика; на слабом телефоне браузеру ещё нужно разобрать и выполнить этот код, прежде чем страница начнёт откликаться

React, React с серверной отрисовкой или без фреймворка

Три частых подхода рядом. React с серверной отрисовкой — это фреймворки вроде Next.js.

КритерийReact в браузереReact + сервер (Next.js)Серверный HTML без фреймворка
Первый экран после загрузки и выполнения JavaScript приходит готовым, потом оживает приходит готовым
Содержание для поисковиков только после JavaScript в HTML в HTML
Вес JavaScript десятки КБ и больше десятки КБ и больше только то, что нужно странице
Сложные интерактивные экраны сильная сторона сильная сторона сложнее, когда множатся состояния
Хостинг любой статический сервер на Node.js или платформа любой, включая виртуальный
Зависимости для обновления много много, плюс фреймворк мало
Проект через пять лет требует регулярных обновлений следует за изменениями фреймворка работает как написан
Разработчиков на рынке очень много много любой веб-разработчик
Лучше всего для кабинетов, SaaS, Mini Apps крупных продуктов с публичными страницами сайтов, лендингов, каталогов, блогов

Что браузер умеет без фреймворка сегодня

Многое, для чего раньше нужна была библиотека, теперь встроено в HTML и CSS — вместе с доступностью.

  1. Модальные окна

    <dialog> даёт затемнение фона, закрытие по Esc и удерживает фокус внутри.

  2. Всплывающие окна и меню

    Атрибут popover открывает и закрывает их без единой строки JavaScript.

  3. Аккордеоны

    <details> и <summary> — и содержание остаётся видимым для поисковиков.

  4. Проверка форм

    required, type="email", pattern и понятные сообщения от самого браузера.

  5. Переходы между страницами

    View Transitions анимируют переход между страницами, как в приложении.

  6. Адаптивные компоненты

    Контейнерные запросы и :has() подстраивают блок под его место без скриптов.

Какой подход под какой проект

Двенадцать типичных проектов с рекомендацией и причиной.

ПроектБратьПочему
Лендинг без фреймворка скорость на телефоне решает конверсию
Корпоративный сайт без фреймворка содержание, поиск и форма
Блог или медиа без фреймворка страницы читают, а не работают в них
Каталог с фильтрами без фреймворка или островки страницы для поиска, фильтры — небольшим скриптом
Интернет-магазин островки серверные страницы, React в корзине и оформлении, если они сложные
Калькулятор на сайте островок один интерактивный блок на обычной странице
Личный кабинет React много состояний и живые данные
Дашборд или админка React таблицы, фильтры и редактирование на одном экране
SaaS-продукт React интерфейс и есть продукт
Telegram Mini App React приложение внутри мессенджера
Редактор или конструктор React перетаскивание, отмена, живой предпросмотр
Крупный продукт с публичными страницами Next.js React везде, но страницы приходят готовыми для поиска

Золотая середина: островки

Страница собирается на сервере обычным HTML — быстрая, видимая поисковикам, работающая без JavaScript. Там, где блоку действительно нужно жить, — калькулятор, конфигуратор, корзина, — React подключается только в этот блок. Остальная страница за него не платит.

Так же работают и инструменты полегче: Preact даёт подход React в несколько килобайт, htmx и Alpine.js добавляют поведение атрибутами, а Astro собирает из островков целые сайты. Выбор зависит от команды и от того, насколько вырастет интерактивная часть.

  • Страница — HTML с сервера
  • React — только там, где блок живёт
  • Остальная страница не платит

Одни задачи на React и без него: 5 примеров

Модальное окно и поиск по списку двумя способами плюс островок. React-примеры проверены TypeScript 7 в строгом режиме, HTML-примеры — в Chromium.

Модальное окно: React

Состояние в компоненте; закрытие по Esc и удержание фокуса нужно писать отдельно.

Subscribe.tsx
import { useState } from 'react';

// React: состояние окна живёт в компоненте, а Esc и фокус — ваша забота
export function Подписаться() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <button onClick={() => setOpen(true)}>Подписаться</button>
      {open && (
        <div role="dialog" aria-modal="true" className="modal">
          <p>Оставьте почту — пишем раз в месяц.</p>
          <button onClick={() => setOpen(false)}>Закрыть</button>
        </div>
      )}
    </>
  );
}

Модальное окно: без фреймворка

Работу делает <dialog>: затемнение, Esc и фокус даёт браузер.

subscribe.html
<!-- без фреймворка: Esc, фокус и затемнение фона браузер берёт на себя -->
<button id="open">Подписаться</button>

<dialog id="subscribe">
  <p>Оставьте почту — пишем раз в месяц.</p>
  <form method="dialog"><button>Закрыть</button></form>
</dialog>

<script>
  document.getElementById('open').addEventListener('click', () => {
    document.getElementById('subscribe').showModal();
  });
</script>

Поиск по списку: React

Список строится в браузере — пока JavaScript не выполнится, на странице ничего нет.

Search.tsx
import { useState } from 'react';

const products = ['Дубовый стол', 'Дубовый стул', 'Сосновая полка', 'Ореховый стол'];

// React: список строит JavaScript в браузере
export function Search() {
  const [query, setQuery] = useState('');
  const found = products.filter((p) => p.toLowerCase().includes(query.toLowerCase()));
  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Поиск" />
      <ul>
        {found.map((p) => (
          <li key={p}>{p}</li>
        ))}
      </ul>
    </>
  );
}

Поиск по списку: без фреймворка

Список приходит с сервера и виден сразу, а скрипт только прячет то, что не подходит.

search.html
<!-- список приходит с сервера: его видят поисковики, а JavaScript только скрывает лишнее -->
<input id="q" type="search" placeholder="Поиск">
<ul id="list">
  <li>Дубовый стол</li>
  <li>Дубовый стул</li>
  <li>Сосновая полка</li>
  <li>Ореховый стол</li>
</ul>

<script>
  const items = [...document.querySelectorAll('#list li')];
  document.getElementById('q').addEventListener('input', (e) => {
    const q = e.target.value.toLowerCase();
    for (const li of items) li.hidden = !li.textContent.toLowerCase().includes(q);
  });
</script>

Островок: React в одном блоке

Страница остаётся серверным HTML, а React подключается только туда, где должен жить калькулятор.

calculator.tsx
import { createRoot } from 'react-dom/client';
import { Calculator } from './Calculator';

// страница — обычный серверный HTML, а React живёт в одном блоке
const mount = document.getElementById('calculator');
if (mount) {
  createRoot(mount).render(<Calculator rate={Number(mount.dataset.rate)} />);
}

Частые ошибки при выборе

  1. Лендинг как одностраничное приложение

    Посетитель из рекламы ждёт JavaScript на слабом телефоне — и уходит до первого экрана.

  2. Содержание только в браузере

    Поисковики читают его хуже, а большинство ИИ-роботов вообще не выполняют JavaScript.

  3. Дашборд на разрозненных скриптах

    Без модели состояния каждая новая функция ломает две старые.

  4. React ради одной кнопки

    Десятки килобайт ради того, что <dialog> или popover делают сами.

  5. Выбирать по привычке команды

    Инструмент выбирает задача, а не наоборот.

  6. Забыть про обновления

    Проект на фреймворке, брошенный на два года, требует переезда раньше любой новой функции.

Вопросы о React и сайтах без фреймворка

Нужен ли сайту React?

Сайту, который читают, — обычно нет. Интерфейсу, в котором работают, — обычно да.

Хуже ли сайт на React для SEO?

Если содержание строится только в браузере — да. С серверной отрисовкой (Next.js) содержание есть в HTML, и проблема уходит.

Сколько весит React?

Минимальное приложение на React 19, собранное Vite, — около 66 КБ в gzip до вашего кода; та же кнопка на чистом JavaScript — полкилобайта.

Сложнее ли поддерживать сайт без фреймворка?

Для контентных сайтов — наоборот: меньше зависимостей, меньше обновлений, и код прочитает любой веб-разработчик.

Можно ли добавить React потом?

Да, островками: новый интерактивный блок получает React без переписывания сайта.

Что такое Next.js?

Фреймворк для React, который собирает страницы на сервере, чтобы они приходили готовыми для людей и поисковиков.

А как же Vue или Svelte?

Логика та же: это инструменты для живых интерфейсов. Svelte компилируется в меньший JavaScript, но вопрос «живёт ли экран?» остаётся.

Не будет ли сайт без фреймворка выглядеть устаревшим?

Внешний вид от фреймворка не зависит: анимации, переходы и современная вёрстка делаются средствами CSS и самого браузера.

Форма

React или
свой код

Подбираю подход под задачу: React с TypeScript там, где интерфейс работает как приложение, и быстрый серверный HTML без фреймворка везде, где это не нужно. Расскажите о проекте — отвечу в течение рабочего дня.

Или пишите на [email protected]