Skip to Content
VueComposition API

Composition API

Уровень: middle.

Вопрос

Зачем Composition API, если Options API уже группирует data, methods и computed?

Короткий ответ

Options API группирует код по виду опции. Фича «фильтр списка» размазывается по data, computed и methods. Composition API группирует по фиче: состояние, вычисления и действия лежат рядом и уезжают в функцию useSomething.

<script setup> — синтаксис одного setup на компонент. Верхнеуровневые привязки сами попадают в шаблон. Пропсы объявляют через defineProps, события через defineEmits. Макрос defineExpose явно отдаёт наружу то, что родитель может взять через ref шаблона. Без него экземпляр из script setup закрыт.

Options API во Vue 3 не удалён. Для короткого компонента он по-прежнему читается линейно.

Миксины Vue 2 для той же задачи хуже. Несколько миксинов кладут поля на this без явного источника, одинаковые имена молча затирают друг друга, параметры передавать неудобно. Composable — функция: const { data: userData } = useUser(), конфликт имён решается при деструктуризации, аргументом может быть ref.

Разбор

Composable — обычная функция, которая вызывает ref, computed и хуки жизненного цикла. Её можно вызвать только синхронно внутри setup, потому что Vue привязывает эффекты к текущему экземпляру.

<script setup lang="ts"> const props = defineProps<{ query: string }>() const emit = defineEmits<{ change: [value: string] }>() const text = ref(props.query) watch(() => props.query, (value) => { text.value = value }) </script>

Типы пропсов в defineProps<{...}>() выводятся для шаблона. Значения по умолчанию для сложных пропсов задают через withDefaults, чтобы не мутировать вход.

watch на проп нужен, когда локальная копия должна догонять родителя. Если локальной копии нет, проп читают напрямую в computed.

На что смотрят на senior

Composable без экземпляра компонента (вызов в обычном модуле) не имеет владельца для onUnmounted. Подписку тогда останавливают вручную. Общий синглтон на модуле удобен для редкого глобального состояния и опасен в тестах: модуль помнит данные между кейсами.

Граница такая: один экран — состояние в компоненте. Два экрана делят сценарий — composable. Данные приложения, которые живут дольше маршрута, — Pinia, а не модульный ref «потому что так проще».

Типичные ошибки

  • Вызывать composable внутри обычной функции обработчика, уже после setup.
  • Эмитить события, не перечисленные в defineEmits, и ловить их потом в $attrs.
  • Тащить в composable и запрос, и вёрсточные строки, и роутер сразу, пока функцию нельзя прочитать без компонента.

Задача

useQuery внутри вызывает onUnmounted и watch. Его вызвали из обработчика клика, не из setup. Что сломается?

Показать ответ

Хуки жизненного цикла и watch привязываются к текущему экземпляру, пока выполняется setup. В клике этого контекста уже нет, Vue предупредит, что onUnmounted вызван вне setup.

Подписка либо не встанет, либо не будет снята вместе с компонентом. Composable вызывают синхронно в setup / <script setup>. В клике вызывают уже возвращённую функцию вроде reload().

Last updated on