ЧаВо по Composition API
Примечание
Этот ЧаВо предполагает предварительный опыт работы с Vue — в частности, опыт работы с Vue 2 при основном использовании Options API.
Что такое Composition API?
Composition API — это набор API, который позволяет нам создавать компоненты Vue, используя импортированные функции вместо объявления опций. Это общий термин, который охватывает следующие API:
Reactivity API, например,
ref()
иreactive()
, что позволяет нам напрямую создавать реактивное состояние, вычисляемое состояние и наблюдателей.Хуки жизненного цикла, например,
onMounted()
иonUnmounted()
, которые позволяют нам программно подключаться к жизненному циклу компонента.Внедрение зависимостей, т. е.
provide()
иinject()
, которые позволяют нам использовать систему внедрения зависимостей Vue при работе с API Reactivity.
Compostion API является встроенной функцией Vue 3 и Vue 2.7. Для старых версий Vue 2 используйте официально поддерживаемый плагин @vue/composition-api
. В Vue 3 он также в основном используется вместе с синтаксисом <script setup>
в однофайловых компонентах. Вот базовый пример компонента, использующего Composition API:
vue
<script setup>
import { ref, onMounted } from 'vue'
// реактивное состояние
const count = ref(0)
// функции, изменяющие состояние и запускающие обновления
function increment() {
count.value++
}
// хуки жизненного цикла
onMounted(() => {
console.log(`Начальное значение: ${count.value}.`)
})
</script>
<template>
<button @click="increment">Счётчик: {{ count }}</button>
</template>
Несмотря на стиль API, основанный на композиции функций, Composition API - это НЕ функциональное программирование. Compostion API основан на парадигме Vue, основанной на мутабельной и мелкозернистой реактивности, в то время как функциональное программирование делает акцент на неизменяемости.
Если вы хотите узнать, как использовать Vue с Composition API, вы можете установить стиль Composition API для всего сайта с помощью переключателя в верхней части левой боковой панели, а затем пройти руководство с самого начала.
Почему Composition API?
Лучшее повторное использование логики
Основное преимущество Composition API заключается в том, что он обеспечивает чистое и эффективное повторное использование логики в виде композаблов. Он решает все недостатки примесей, основного механизма повторного использования логики для Options API.
Возможность повторного использования логики в Composition API породила такие впечатляющие проекты сообщества, как VueUse, постоянно растущую коллекцию композаблов. Он также служит чистым механизмом для лёгкой интеграции сторонних сервисов или библиотек с поддержкой состояния в систему реактивности Vue, например неизменяемые данные, конечные автоматы и RxJS.
Более гибкая организация кода
Многим пользователям нравится, что мы по умолчанию пишем организованный код с помощью Options API: всё имеет свое место в зависимости от того, к какому варианту оно относится. Однако Options API накладывает серьёзные ограничения, когда логика отдельного компонента перерастает определённый порог сложности. Это ограничение особенно заметно в компонентах, которые должны иметь дело с несколькими логическими проблемами, что мы воочию наблюдали во многих продакшен-приложениях Vue 2.
В качестве примера возьмем компонент проводника папок из графического интерфейса Vue CLI: этот компонент отвечает за следующие логические задачи:
- Отслеживание текущего состояния папки и отображение её содержимого
- Работа с навигацией по папкам (открытие, закрытие, обновление...)
- Обработка создания новых папок
- Переключение показа только избранных папок
- Переключение показа скрытых папок
- Обработка изменений текущего рабочего каталога
Оригинальная версия компонента была написана на Options API. Если мы присвоим каждой строке кода цвет в зависимости от логической проблемы, с которой она имеет дело, это будет выглядеть следующим образом:

Обратите внимание, как код, работающий с одной и той же логической проблемой, вынужден быть разделен на разные опции, расположенные в разных частях файла. В компоненте, состоящем из нескольких сотен строк, понимание и навигация по одной логической проблеме требует постоянного прокручивания файла вверх и вниз, что значительно усложняет задачу. Кроме того, если мы собираемся извлечь логическую проблему в утилиту многократного использования, то поиск и извлечение нужных фрагментов кода из разных частей файла займет немало времени.
Вот тот же компонент, до и после рефакторинга в Composition API:
Обратите внимание, что код, относящийся к одной и той же логической задаче, теперь можно сгруппировать: нам больше не нужно перескакивать между различными блоками опций при работе над конкретной логической проблемой. Более того, теперь мы можем перенести группу кода во внешний файл с минимальными усилиями, поскольку нам больше не нужно перемешивать код, чтобы извлечь его. Такое снижение трения при рефакторинге является ключевым фактором для долгосрочной поддерживаемости больших кодовых баз.
Улучшенный вывод типа
В последние годы всё больше и больше разработчиков внешнего интерфейса используют TypeScript, поскольку он помогает нам писать более надежный код, вносить изменения с большей уверенностью и обеспечивает отличный опыт разработки с поддержкой IDE. Однако Options API, первоначально задуманный в 2013 году, был разработан без учёта вывода типа. Нам пришлось реализовать некоторую абсурдно сложную гимнастику типов, чтобы вывод типа работал с Options API. Даже несмотря на все эти усилия, вывод типа для Options API всё равно может не работать из-за примесей и внедрения зависимостей.
Это побудило многих разработчиков, которые хотели использовать Vue с TS, склониться к Class API на базе vue-class-component
. Однако API на основе классов в значительной степени опирается на декораторы ES — функцию языка, которая была предложена только на этапе 2, когда Vue 3 разрабатывалась в 2019 году. Мы посчитали, что слишком рискованно основывать официальный API на нестабильном предложении. С тех пор предложение декораторов претерпело ещё одну полную переработку и, наконец, достигло стадии 3 в 2022 году. Кроме того, API на основе классов страдает от повторного использования логики и организационных ограничений, аналогичных Options API.
Для сравнения, Composition API использует в основном простые переменные и функции, которые, естественно, дружественны к типам. Код, написанный с помощью Composition API, может использовать полный вывод типов без необходимости использования подсказок типа вручную. В большинстве случаев код Composition API будет выглядеть практически одинаково в TypeScript и простом JavaScript. Это также позволяет пользователям простого JavaScript получить выгоду от частичного вывода типов.
Меньший производственный комплекс и меньшие накладные расходы
Код, написанный с использованием Composition API и <script setup>
, также более эффективен и удобен для минимизации, чем эквивалент Options API. Это связано с тем, что шаблон в компоненте <script setup>
компилируется как функция, встроенная в ту же область действия, что и <script setup>
. В отличие от доступа к свойствам из this
, скомпилированный код шаблона может напрямую обращаться к переменным, объявленным внутри <script setup>
, без прокси-сервера между ними. Это также приводит к лучшей минимизации, поскольку все имена переменных можно безопасно сократить.
Связь с Options API
Компромиссы
Некоторые пользователи, перешедшие с Options API, обнаружили, что их код Composition API менее организован, и пришли к выводу, что Composition API «хуже» с точки зрения организации кода. Мы рекомендуем пользователям с таким мнением взглянуть на эту проблему с другой точки зрения.
Это правда, что Composition API больше не предоставляет «ограждения», которые помогут вам поместить ваш код в соответствующие сегменты. Взамен вы получаете возможность создавать код компонента так же, как если бы вы писали обычный JavaScript. Это означает, что вы можете и должны применять любые передовые методы организации кода к коду Composition API, как если бы вы писали обычный JavaScript. Если вы умеете писать хорошо организованный JavaScript, вы также сможете писать хорошо организованный код Composition API.
Options API позволяет вам «меньше думать» при написании кода компонента, поэтому многим пользователям он нравится. Однако, сокращая умственные затраты, он также привязывает вас к предписанному шаблону организации кода без каких-либо выходных люков, что может затруднить рефакторинг или улучшение качества кода в крупномасштабных проектах. В этом отношении Composition API обеспечивает лучшую долгосрочную масштабируемость.
Охватывает ли Composition API все варианты использования??
Да, с точки зрения логики состояния. При использовании Composition API может потребоваться всего несколько опций: props
, emits
, name
, и inheritAttrs
.
Совет
Начиная с версии 3.3, вы можете напрямую использовать defineOptions
в <script setup>
, чтобы установить имя компонента или свойство inheritAttrs
.
Если вы намерены использовать исключительно Composition API (наряду с опциями, перечисленными выше), вы можете сократить свой продакшен-пакет на несколько КБ с помощью флага на этапе компиляции, который удаляет код, связанный с Options API, из Vue. Обратите внимание, что это также влияет на компоненты Vue в ваших зависимостях.
Могу ли я использовать оба API в одном компоненте?
Да. Вы можете использовать Composition API с помощью параметра setup()
в компоненте Options API.
Однако мы рекомендуем делать это только в том случае, если у вас есть существующая кодовая база Options API, которую необходимо интегрировать с новыми функциями/внешними библиотеками, написанными с помощью Composition API.
Будет ли Options API устаревшим?
Нет, у нас нет никаких планов по этому поводу. Options API — неотъемлемая часть Vue и причина, по которой он нравится многим разработчикам. Мы также понимаем, что многие преимущества Composition API проявляются только в крупномасштабных проектах, а Options API остаётся надежным выбором для многих сценариев низкой и средней сложности.
Связь с Class API
Мы больше не рекомендуем использовать Class API с Vue 3, поскольку Composition API обеспечивает отличную интеграцию TypeScript с дополнительными преимуществами повторного использования логики и организации кода.
Сравнение с React Hooks
Composition API обеспечивает тот же уровень возможностей логической композиции, что и React Hooks, но с некоторыми важными отличиями.
React Hooks вызываются повторно каждый раз при обновлении компонента. Это создает ряд предостережений, которые могут сбить с толку даже опытных разработчиков React. Это также приводит к проблемам с оптимизацией производительности, которые могут серьезно повлиять на опыт разработки. Вот некоторые примеры:
Хуки чувствительны к порядку вызовов и не могут быть условными.
Переменные, объявленные в компоненте React, могут быть захвачены замыканием хука и стать «устаревшими», если разработчик не может передать правильный массив зависимостей. Это приводит к тому, что разработчики React полагаются на правила ESLint, чтобы гарантировать передачу правильных зависимостей. Однако правило часто недостаточно умно и чрезмерно компенсирует правильность, что приводит к ненужной недействительности и головной боли при возникновении крайних случаев.
Дорогие вычисления требуют использования
useMemo
, что опять же требует ручной передачи правильного массива зависимостей.Обработчики событий, передаваемые дочерним компонентам, по умолчанию вызывают ненужные дочерние обновления и требуют явного
useCallback
в качестве оптимизации. Это необходимо почти всегда и опять-таки требует правильного массива зависимостей. Пренебрежение этим по умолчанию приводит к перерисовке приложений и может вызвать проблемы с производительностью, даже не осознавая этого.Проблема устаревшего закрытия в сочетании с параллельными функциями затрудняет определение того, когда запускается часть кода хуков, и делает затруднительной работу с изменяемым состоянием, которое должно сохраняться во время отрисовки (через
useRef
).
Примечание: Некоторые из вышеперечисленных проблем, связанных с мемоизацией, могут быть решены с помощью грядущего компилятора React.
Для сравнения, Vue Composition API:
Вызывает код
setup()
или<script setup>
только один раз. Это позволяет коду лучше соответствовать интуиции использования идиоматического JavaScript, поскольку нет необходимости беспокоиться об устаревших замыканиях. Вызовы Composition API также не чувствительны к порядку вызовов и могут быть условными.Система реактивности среды выполнения Vue автоматически собирает реактивные зависимости, используемые в вычисляемых свойствах и наблюдателях, поэтому нет необходимости объявлять зависимости вручную.
Нет необходимости вручную кэшировать функции обратного вызова, чтобы избежать ненужных дочерних обновлений. В целом, детальная система реактивности Vue гарантирует, что дочерние компоненты обновляются только тогда, когда им это необходимо. Ручная оптимизация дочерних обновлений редко вызывает беспокойство у разработчиков Vue.
Мы признаем креативность React Hooks, и это главный источник вдохновения для Composition API. Однако проблемы, упомянутые выше, действительно существуют в его конструкции, и мы заметили, что модель реактивности Vue позволяет их обойти.