EverProduct
Фронтенд

Этап 04 · Приложение

Кукловод: какую задачу на самом деле решают фреймворки

Фреймворки — не мода и не срез углов. Они убирают одну конкретную работу: держать экран и данные в согласии. И увидеть, зачем её убирать, можно, только сделав её руками.

Возьми список дел, который ты собрал руками в статье про DOM, и добавь в него обычные вещи.

Счётчик незавершённых. Фильтр «все / активные / выполненные». Кнопку «очистить выполненные». Режим редактирования отдельной строки. Чекбокс «выбрать все», отражающий, всё ли отмечено.

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

Код не трудный. Он бесконечно бухгалтерский, и баги, которые он рождает, все одинаковые: что-то на экране тихо расходится со стоящими за ним данными.

Фреймворк не рисует твой экран. Он убирает работу по описанию каждого перехода от одного экрана к следующему.

Одна идея

Любой современный фреймворк стоит на одном уравнении: интерфейс есть функция состояния.

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

В этом весь сдвиг, и его стоит проговорить в двух словарях, которыми пользуются люди. Старый способ императивен: последовательность инструкций, как попасть с текущего экрана на следующий. Новый декларативен: описание пункта назначения, а маршрут оставлен машине. Та же разница, что между «поверни здесь, потом там» и адресом.

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

Как они это делают

Реализации разные, и знать об их различии важно, потому что одну реализацию часто принимают за саму идею.

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

Svelte делает работу на этапе сборки: компилятор читает компонент и генерирует код, обновляющий ровно нужные узлы, поэтому сравнивать во время работы нечего.

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

Три разные стратегии и одно одинаковое обещание: ты описываешь результат, машина находит разницу. А значит, изучаемые понятия — состояние, пропсы, компоненты, производные значения, эффекты — переносятся между ними, а синтаксис нет. Выучи понятия — и второй фреймворк обойдётся в неделю.

Компоненты и разделение, которое понимают неверно

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

Поколению, воспитанному на «раздели структуру, оформление и поведение по разным файлам», это казалось ошибкой. Но то правило разделяло по технологии и порождало три файла, которые можно было понять только вместе и менять только вместе. Компоненты разделяют по функциональности: всё про поле поиска лежит в одном месте, и удалить его можно без археологии.

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

JSX в одном абзаце

Если ты учишь React, ты встретишь JSX, и он вызывает вполне конкретную путаницу, которую стоит снять сразу: это не HTML внутри JavaScript. Это синтаксис, компилирующийся в обычные вызовы функций, возвращающих объекты. Поэтому class превращается в className, поэтому имена атрибутов в camelCase и поэтому внутрь можно положить любое выражение JavaScript: ты строишь структуру данных, а не пишешь разметку.

Понимание этой одной фразы предотвращает класс путаницы, который иначе тянется месяцами.

Чего это стоит

Честный список, потому что фреймворки обычно продают без него.

Вес и сложность. Фреймворк — это код, уезжающий каждому пользователю, плюс сборка, плюс набор соглашений, которые надо выучить. Для страницы со статичным содержимым это чистые издержки.

Текучесть. Экосистема движется. Ответы в интернете могут описывать версию трёхлетней давности, а учебник, по которому ты учился, может уже преподавать не рекомендуемый подход. Это неудобно и превращает чтение официальной документации в настоящий навык, а не в запасной вариант.

Изучение фреймворка вместо языка. Вот это дорого. Человек, начавший с React, соберёт страницу и не сможет объяснить, что возвращает map, почему его массив не вызвал перерисовку и что делать, когда фреймворк не является ответом. У сферы «Как учиться» есть имя для формы такого провала — заклинивший ключ, метод, отработанный настолько, что альтернативы перестают быть видны. Всё становится задачей про React, включая задачи, которые не про него.

Именно поэтому предыдущий этап шёл первым. Фреймворк — слой поверх DOM, и он протекает: рано или поздно ты подключишь библиотеку, ждущую настоящий элемент, будешь отлаживать то, что фреймворк сделал с твоим событием, или тебе понадобится обычный скрипт. Знание нижнего слоя не опционально.

Когда он не нужен

Стоит сказать прямо, потому что это немодно: очень многим страницам фреймворк не нужен.

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

Сигнал, что фреймворк всё-таки нужен, — общее состояние, которое появляется в нескольких местах и меняется со временем. Дашборды, редакторы, всё с корзиной, всё с живыми данными. Это и есть та бухгалтерия, против которой фреймворк отрабатывает свой вес.

Как выбирать и что на самом деле переносится

У React самая большая экосистема и больше всего вакансий, поэтому он и есть ответ по умолчанию, если ты учишься ради работы. Vue славится доступностью. Svelte — самое маленькое, что нужно держать в голове. Solid и поколение на сигналах — там, куда ушла значительная часть свежей мысли. Angular остаётся стандартом в определённого типа крупных организациях.

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

И предупреждение из того же места: освоив один, намеренно посмотри один раз, как ту же задачу решает другой. Не чтобы перейти — чтобы увидеть форму идеи отдельно от одной её реализации. Понимать — значит уметь смотреть на объект более чем с одного ракурса, а единственный фреймворк, видимый изнутри, — это ровно один ракурс.

На практике

Сначала почувствуй проблему. Если ты ещё не собирал руками то, где одно значение появляется в трёх местах, сделай это до продолжения. Двадцать минут — и у всего дальнейшего появляется причина.

Переведи ту же самодельную вещь во фреймворк. Тот же набор функций, тот же вечер. Урок — в сравнении, и оно поучительнее нового учебного проекта.

Проговаривай состояние вслух до написания компонента. Что этому куску интерфейса нужно знать, чтобы себя нарисовать? Этот вопрос — девять десятых проектирования, и следующая статья целиком о том, как хорошо на него отвечать.

Читай официальную документацию, а не учебники. Документация фреймворков в наши дни необычайно хороша, и это та версия, которая не устарела на три года.

Полгода сопротивляйся второму фреймворку. Глубина переносится; ширина на этом этапе — нет.

Проверь себя

Закрой статью и ответь своими словами:

  1. Какую именно работу снимает с тебя фреймворк и почему она растёт быстрее списка функций?
  2. Что означает «интерфейс есть функция состояния» на практике?
  3. Дай по одному предложению на разницу между императивным и декларативным.
  4. Назови три разные стратегии реализации и то, что у них общего.
  5. Почему «компоненты смешивают HTML, CSS и JS» — не нарушение разделения ответственности?
  6. Что такое JSX на самом деле и что это объясняет?
  7. Когда фреймворк — неверный выбор?

Коротко

  • Собери руками что-нибудь настоящее — и бухгалтерия между данными и DOM вырастет быстрее, чем список функций; эту работу и убирает фреймворк.
  • Любой фреймворк стоит на одном уравнении: интерфейс есть функция состояния, описанная декларативно вместо императивных переходов.
  • Виртуальный DOM, компиляция и сигналы — три стратегии одного обещания, поэтому понятия переносятся, хотя синтаксис нет.
  • Компоненты разделяют по функциональности, а не по технологии, и должны оставаться достаточно маленькими, чтобы помещаться в голове.
  • JSX — не HTML в JavaScript: он компилируется в вызовы функций, возвращающих объекты, и это объясняет бо́льшую часть его странностей.
  • Издержки — вес, текучесть экосистемы и серьёзный риск выучить фреймворк вместо языка под ним.
  • Статичным страницам, формам и мелким виджетам фреймворк часто не нужен; сигнал, что нужен, — общее состояние в нескольких местах.
  • Учи один фреймворк глубоко вместо дегустации четырёх, а потом один раз посмотри на другой — чтобы увидеть идею отдельно от одной реализации.