1. Основы Vue.js и парадигма Composition API
Основы Vue.js и парадигма Composition API
Представьте, что вы строите сложный механизм, где каждая деталь должна не только выполнять свою функцию, но и мгновенно реагировать на изменения в соседних узлах. В классическом JavaScript (Vanilla JS) вам пришлось бы вручную искать каждый элемент в DOM, подписываться на события и обновлять текст или атрибуты при каждом изменении данных. Это напоминает управление марионеткой, где к каждой конечности привязано по десятку нитей: стоит добавить одно новое движение, и нити начинают путаться. Vue.js предлагает иной подход — декларативность. Вы описываете, как должен выглядеть интерфейс в зависимости от состояния данных, а фреймворк берет на себя всю рутину по обновлению «нитей».
Философия прогрессивного фреймворка
Vue.js часто называют «прогрессивным» фреймворком. Это не просто маркетинговый эпитет, а фундаментальное архитектурное решение. В отличие от монолитных инструментов, которые требуют принятия всех своих правил игры сразу, Vue позволяет внедрять себя постепенно. Вы можете использовать его как легкую библиотеку для оживления одной кнопки на старой странице или как мощный фундамент для огромного одностраничного приложения (SPA).
В основе Vue лежит концепция реактивности. Это означает, что связь между данными (состоянием) и представлением (HTML) является живой. Как только значение переменной в JavaScript меняется, Vue автоматически вычисляет, какие части интерфейса зависят от этой переменной, и точечно обновляет их. Это достигается за счет использования виртуального DOM (Virtual DOM) — легковесной копии реального дерева элементов, которая позволяет минимизировать дорогостоящие операции в браузере.
От Options API к Composition API: эволюция мысли
Долгое время основным способом написания компонентов во Vue был Options API. Он предлагал жесткую структуру: данные в секции data, методы в methods, вычисляемые свойства в computed. Для новичков это было спасением — всегда понятно, куда писать код. Однако по мере роста приложений возникла проблема «разбросанной логики». Если у вас есть сложная фича (например, поиск с фильтрацией), код для неё оказывался размазан по всем секциям компонента.
Composition API, появившийся во Vue 3, радикально меняет этот подход. Вместо того чтобы разделять код по типу (данные к данным, методы к методам), он позволяет группировать код по логическому смыслу.
> «Composition API — это не просто новый синтаксис, это способ организации мышления, позволяющий извлекать и переиспользовать логику так же легко, как мы извлекаем функции в обычном программировании».
Это особенно важно в больших проектах, где один компонент может занимать сотни строк. В Composition API вся логика сосредоточена внутри функции setup() (или, в современном стандарте, внутри блока <script setup>).
Анатомия компонента и точка входа setup
Современный компонент Vue — это файл с расширением .vue, который объединяет в себе три сущности: структуру (HTML), логику (JS/TS) и оформление (CSS). Это называется Single File Component (SFC).
Рассмотрим базовую структуру с использованием <script setup>:
В этом примере ref — это функция, которая делает переменную реактивной. Без неё изменение count осталось бы незамеченным для интерфейса. Обратите внимание на свойство .value: в блоке скрипта мы обращаемся к значению через него, но в шаблоне (template) Vue автоматически «распаковывает» объект, и мы пишем просто count.
Глубокое погружение в реактивность: ref против reactive
Во Vue 3 есть два основных инструмента для создания реактивного состояния: ref() и reactive(). Понимание разницы между ними — это водораздел между любителем и профессионалом.
ref: универсальный солдат
ref принимает любое значение (число, строку, массив или объект) и оборачивает его в специальный объект-контейнер.
.value в JavaScript.reactive: работа со сложными структурами
reactive работает только с объектами (включая массивы и коллекции вроде Map/Set). Он делает сам объект реактивным «изнутри».
Здесь нам не нужно писать state.value.user. Мы обращаемся напрямую: state.user. Однако у reactive есть коварная особенность: при деструктуризации объекта реактивность теряется.
Если вы хотите разложить реактивный объект на отдельные переменные, сохранив связь, нужно использовать вспомогательную функцию toRefs(). В современной практике сообщество всё чаще склоняется к использованию ref даже для объектов, чтобы сохранить единообразие и избежать проблем с деструктуризацией.
Вычисляемые свойства (Computed)
Часто нам нужно не просто отобразить данные, а трансформировать их. Например, у нас есть массив товаров, а мы хотим показать общую стоимость корзины. Можно было бы написать логику прямо в шаблоне, но это плохой тон. Для этого существуют computed.
Вычисляемое свойство — это производное состояние. Его главная особенность — кэширование. Если данные, от которых зависит computed, не изменились, Vue не будет пересчитывать значение, а просто вернет результат предыдущего вычисления.
Представим систему фильтрации списка пользователей:
Если в списке 10 000 имен, а пользователь просто кликает по кнопке «Сменить тему оформления» (которая не влияет на search или users), filteredUsers не будет пересчитываться. Это критически важно для производительности.
Наблюдатели (Watchers)
Иногда нам нужно выполнить «побочный эффект» в ответ на изменение данных: отправить запрос к API, сохранить что-то в LocalStorage или запустить анимацию. Для этого используется watch.
В отличие от computed, который должен быть «чистой» функцией и возвращать значение, watch просто следит за источником и вызывает колбэк.
Такой подход обеспечивает предсказуемость интерфейса. Мы можем использовать v-if="isLoading" для отображения спиннера и v-else-if="error" для вывода сообщения об ошибке.
Сравнение подходов: когда и что выбирать
Хотя Composition API является стандартом для Vue 3, Options API всё еще поддерживается. Для маленьких компонентов или пет-проектов Options API может показаться проще. Но как только вы переходите к командной разработке или сложным интерфейсам, Composition API становится незаменимым.
| Характеристика | Options API | Composition API | | :--- | :--- | :--- | | Организация кода | По типам опций (data, methods) | По логическим задачам | | Переиспользование | Миксины (могут конфликтовать) | Composables (чистые функции) | | Поддержка TypeScript | Ограниченная | Отличная (нативная) | | Читаемость | Хорошая для простых компонентов | Идеальная для сложных структур |
Ошибки новичков и как их избежать
Одной из самых частых ошибок является попытка использовать реактивность там, где она не нужна. Не каждую переменную стоит оборачивать в ref. Если данные статичны и никогда не изменятся в течение жизни компонента, оставьте их обычными константами. Это сэкономит ресурсы памяти и процессора.
Вторая ошибка — «забытый» .value. Если вы видите в консоли странный объект вместо числа, скорее всего, вы забыли обратиться к значению ref внутри функции.
Третья проблема — мутация пропсов. Пропсы (входящие данные от родителя) во Vue являются неизменяемыми (read-only). Если вам нужно изменить данные, полученные от родителя, вы должны отправить событие (emit) наверх, чтобы родитель сам обновил свое состояние. Это принцип «Data down, events up», который обеспечивает односторонний поток данных и делает приложение предсказуемым.
Взгляд в будущее
Освоение Composition API — это первый и самый важный шаг. Это фундамент, на котором строятся все остальные части экосистемы: от управления состоянием в Pinia до серверного рендеринга в Nuxt.js. Понимая, как работают ref, computed и хуки жизненного цикла, вы перестаете бороться с фреймворком и начинаете использовать его мощь для создания интерфейсов, которые ощущаются пользователями как мгновенные и бесшовные.
В следующих главах мы разберем, как эти кирпичики складываются в сложные системы взаимодействия компонентов, и как научить их общаться между собой, не превращая код в «спагетти».