Vue3 Composition API
Vue3 Composition API в основном используется для повышения переиспользуемости логики кода в больших компонентах.
По мере роста сложности бизнеса традиционные компоненты продолжают увеличиваться в объёме кода, и всю логику кода становится трудно читать и понимать.
Место, где Vue3 использует Composition API, — это функция setup().setup。
В setup мы можем группировать части кода по логическим задачам, затем извлекать фрагменты логики и делиться ими с другими компонентами. Поэтому Composition API позволяет нам писать более организованный код.
Сравните следующие два фрагмента кода:
1. Традиционные компоненты

2. Composition API

Компонент setup
Функция setup() выполняется до создания компонента (created()).
Функция setup() принимает два параметра: props и context.
Первый параметр, props, является реактивным и будет обновляться при передаче новых props.
Второй параметр, context, — это обычный объект JavaScript. Это объект контекста, который предоставляет другие значения, которые могут быть полезны в setup.
Примечание:В setup следует избегать использования this, потому что он не найдёт экземпляр компонента. Вызов setup происходит до того, как будут разрешены свойства data, вычисляемые свойства или методы, поэтому к ним нельзя получить доступ в setup.
В следующем примере используется Composition API для определения счётчика:
Пример (src/APP.vue)
<div>
<p>Пример счетчика: {{ count }}</p>
<input @click="myFn" type="button" value="Нажми меня, чтобы добавить 1">
</div>
</template>
<script>
import {ref, onMounted} from 'vue';
export default {
setup(){
// Определите переменную с начальным значением 0. Используйте метод ref для присваивания; если присвоить напрямую, изменения переменной не будут обновлять UI.
let count = ref(0);
// Определите событие клика myFn
function myFn(){
console.log(count);
count.value += 1;
}
// Когда компонент смонтирован, мы используем хук onMounted, чтобы записать несколько сообщений
onMounted(() => console.log('компонент смонтирован!'));
// Переменные или методы, определённые с помощью Composition API, доступны в шаблоне.
return {count, myFn} // Возвращаемые функции ведут себя так же, как методы
}
}
</script>
В Vue 3.0 мы можем использовать новую функцию ref, чтобы любая реактивная переменная работала где угодно, как показано ниже:
import { ref } from 'vue'
let count = ref(0);
ref()Функция создаёт реактивный объект данных на основе заданного значения. Возвращаемое значение — это объект, содержащий только одно.value.value свойство.
В функции setup() реактивные данные, созданные с помощью ref(), возвращают объект, поэтому вам нужно использовать.value.value для доступа.
Пример
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
counter.value++
console.log(counter.value) // 1
Хуки жизненного цикла Vue Composition API
В Vue2 мы реализуем функции-хуки жизненного цикла следующим образом:
Пример
beforeMount() {
console.log('V2 beforeMount!')
},
mounted() {
console.log('V2 mounted!')
}
};
В Vue3 Composition API функции-хуки жизненного цикла можно реализовать вsetup()функции setup() с использованиемonфункций с префиксом on:
Пример
export default {
setup() {
onBeforeMount(() => {
console.log('V3 beforeMount!');
})
onMounted(() => {
console.log('V3 mounted!');
})
}
};
В следующей таблице показано соответствие между Options API и Composition API, включая то, как вызывать хуки жизненного цикла внутри setup():
| API Vue2 на основе Options | Vue Composition API |
|---|---|
| beforeCreate | setup() |
| created | setup() |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeDestroy | onBeforeUnmount |
| destroyed | onUnmounted |
| errorCaptured | onErrorCaptured |
Поскольку setup выполняется вокруг хуков жизненного цикла beforeCreate и created, нет необходимости явно определять их. Иными словами, любой код, написанный в этих хуках, следует писать непосредственно в функции setup.
Эти функции принимают колбэк, который будет выполнен, когда компонент вызовет хук:
Пример
...
// Когда компонент смонтирован, мы используем хук onMounted, чтобы записать несколько сообщений
onMounted(() => console.log('компонент смонтирован!'));
...
}
Ссылки на шаблон
При использовании Composition API реактивные ссылки и ссылки на шаблон — это единые концепции.
Чтобы получить ссылку на элемент или экземпляр компонента в шаблоне, мы можем объявить ref как обычно и вернуть его из setup():
Пример
<div ref="root">Это корневой элемент</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// DOM-элемент будет присвоен ref после первоначального рендеринга
console.log(root.value) // <div>Это корневой элемент</div>
})
return {
root
}
}
}
</script>
В приведённом выше примере мы предоставляем root в контексте рендеринга и привязываем его к div в качестве его ref с помощью ref="root".
Ссылки, используемые в качестве шаблонов, ведут себя как любой другой ref: они реактивны и могут передаваться в составные функции (или возвращаться из них).
Использование в v-for
При использовании внутри v-for ссылки на шаблон не обрабатываются специальным образом в Composition API. Вместо этого используйте function ref для пользовательской обработки:
Пример
<div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }">
{{ item }}
</div>
</template>
<script>
import { ref, reactive, onBeforeUpdate } from 'vue'
export default {
setup() {
const list = reactive([1, 2, 3])
const divs = ref([])
// Не забудьте сбросить ref перед каждым обновлением
onBeforeUpdate(() => {
divs.value = []
})
return {
list,
divs
}
}
}
</script>
Отслеживание ссылок на шаблон
Наблюдение за изменениями шаблонных ссылок может заменить хуки жизненного цикла, продемонстрированные в предыдущих примерах.
Однако ключевое отличие от хуков жизненного цикла состоит в том, что watch() и watchEffect() выполняются до монтирования или обновления DOM, что имеет побочные эффекты: когда наблюдатель запускается, шаблонные ссылки ещё не обновлены.
Пример
<div ref="root">Это корневой элемент</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
// Этот побочный эффект выполняется до обновления DOM, поэтому шаблонная ссылка ещё не содержит ссылку на элемент.
console.log(root.value) // => null
})
return {
root
}
}
}
</script>
Поэтому наблюдатели, использующие шаблонные ссылки, должны определяться с опцией flush: 'post', которая запускает побочные эффекты после обновления DOM, гарантируя, что шаблонные ссылки остаются синхронизированными с DOM и ссылаются на правильный элемент.
Пример
<div ref="root">Это корневой элемент</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
console.log(root.value) // => <div>Это корневой элемент</div>
},
{
flush: 'post'
})
return {
root
}
}
}
</script>
Справочник API
| Порядковый номер | API и описание | Пример |
|---|---|---|
| 1 | setup() Входная функция в Composition API компонента, вызываемая при создании экземпляра компонента и используемая для определения реактивных данных и методов. | export default { setup() { const count = ref(0); return { count }; } } |
| 2 | ref() Создайте реактивную ссылку для обёртывания примитивных типов или объектов. | const count = ref(0) |
| 3 | computed() Создайте вычисляемое значение на основе других реактивных данных. | const doubledCount = computed(() => count.value * 2) |
| 4 | reactive() Создать реактивный объект, подходящий для объектов или массивов. | const state = reactive({ count: 0 }) |
| 5 | readonly() Создать реактивные данные только для чтения, запрещающие изменение. | const state = readonly({ count: 0 }) |
| 6 | watchEffect() Создать реактивный побочный эффект, который автоматически отслеживает связанные с ним реактивные зависимости. | watchEffect(() => { console.log(count.value) }) |
| 7 | watchPostEffect() Побочный эффект, срабатывающий после обновления DOM. | watchPostEffect(() => { console.log('Post effect') }) |
| 8 | watchSyncEffect() Выполнять побочные эффекты синхронно при изменении реактивных зависимостей. | watchSyncEffect(() => { console.log('Synchronized effect') }) |
| 9 | watch() Используется для наблюдения за изменениями реактивных данных; можно указать конкретные реактивные данные или вычисляемые свойства. | watch(count, (newCount) => { console.log(newCount) }) |
| 10 | onWatcherCleanup() Очистить наблюдатель, вызываемый, когда наблюдаемые данные больше не нужны. | watch(count, () => {}, onWatcherCleanup(() => { console.log('cleaned up') })) |
| 11 | isRef() Проверить, относится ли значение к refтипу ref. | isRef(count) |
| 12 | unref() Развернуть refзначение ref. | unref(count) |
| 13 | toRef() Создать реактивный ref, извлечённый из объекта. | const countRef = toRef(state, 'count') |
| 14 | toValue() Развернуть refилиreactiveзначение типа ref. | toValue(count) |
| 15 | toRefs() Преобразовать каждое свойство реактивного объекта в независимый ref. ref。 | const { count } = toRefs(state) |
| 16 | isProxy() Проверить, является ли объект прокси-объектом Vue. | isProxy(state) |
| 17 | isReactive() Проверить, является ли объект реактивным объектом. | isReactive(state) |
| 18 | isReadonly() Проверить, является ли объект реактивным объектом, доступным только для чтения. | isReadonly(state) |
| 19 | shallowRef() Создать поверхностный реактивный объект, refделая реактивными только свойства первого уровня объекта. | const state = shallowRef({ count: 0 }) |
| 20 | triggerRef() Принудительно вызвать refобновление ref. | triggerRef(count) |
| 21 | customRef() Создать пользовательский реактивный ref, позволяющий разработчикам настраивать getter и setter. | const count = customRef((track, trigger) => { let value = 0; return { get: () => value, set: (val) => { value = val; trigger() } } }) |
| 22 | shallowReactive() Создать поверхностный реактивный объект, в котором реактивны только свойства первого уровня объекта. | const state = shallowReactive({ count: 0 }) |
| 23 | shallowReadonly() Создайте поверхностный реактивный объект только для чтения, где только свойства первого уровня объекта доступны только для чтения. | const state = shallowReadonly({ count: 0 }) |
| 24 | toRaw() Получите исходный объект прокси-объекта. | const rawState = toRaw(state) |
| 25 | markRaw() Помечает объект как не подлежащий проксированию, и Vue пропустит реактивную обработку для этого объекта. | const obj = markRaw({ count: 0 }) |
| 26 | effectScope() Создайте новую область видимости эффекта для управления побочными эффектами. | const scope = effectScope() |
| 27 | getCurrentScope() Получите текущую область видимости эффекта. | const scope = getCurrentScope() |
| 28 | onScopeDispose() Выполните функцию очистки при уничтожении области видимости эффекта. | onScopeDispose(() => { console.log('Scope disposed') }) |
| 29 | onMounted() Хук жизненного цикла, вызываемый при монтировании компонента. | onMounted(() => { console.log('Component mounted') }) |
| 30 | onUpdated() Хук жизненного цикла, вызываемый при обновлении компонента. | onUpdated(() => { console.log('Component updated') }) |
| 31 | onUnmounted() Хук жизненного цикла, вызываемый при размонтировании компонента. | onUnmounted(() => { console.log('Component unmounted') }) |
| 32 | onBeforeMount() Хук жизненного цикла, вызываемый перед монтированием компонента. | onBeforeMount(() => { console.log('Before mount') }) |
| 33 | onBeforeUpdate() Хук жизненного цикла, вызываемый перед обновлением компонента. | onBeforeUpdate(() => { console.log('Before update') }) |
| 34 | onBeforeUnmount() Хук жизненного цикла, вызываемый перед размонтированием компонента. | onBeforeUnmount(() => { console.log('Before unmount') }) |
| 35 | onErrorCaptured() Перехват необработанных ошибок в дереве компонентов. | onErrorCaptured((err, instance, info) => { console.error(err) }) |
| 36 | onRenderTracked() Хук, срабатывающий при отслеживании реактивных данных во время рендеринга компонента. | onRenderTracked((event) => { console.log(event) }) |
| 37 | onRenderTriggered() Хук, срабатывающий при изменении реактивных данных во время рендеринга компонента. | onRenderTriggered((event) => { console.log(event) }) |
| 38 | onActivated() Хук жизненного цикла, вызываемый при активации компонента (используется для keep-aliveкомпонента). | onActivated(() => { console.log('Component activated') }) |
| 39 | onDeactivated() Хук жизненного цикла, вызываемый при деактивации компонента (используется для keep-aliveкомпонента). | onDeactivated(() => { console.log('Component deactivated') }) |
| 40 | onServerPrefetch() Хук для предварительной загрузки данных, когда компонент рендерится на стороне сервера. | onServerPrefetch(async () => { await fetchData() }) |
| 41 | provide() Предоставление зависимостей компонентам-потомкам. | provide('key', value) |
| 42 | inject() Внедрение зависимостей от родительских компонентов или компонентов-предков. | const value = inject('key') |
| 43 | hasInjectionContext() Проверка наличия контекста внедрения в данный момент. | hasInjectionContext() |
| 44 | useAttrs() Получение всех атрибутов компонента, включая HTML-атрибуты, переданные компоненту. | const attrs = useAttrs() |
| 45 | useSlots() Получение содержимого слота компонента. | const slots = useSlots() |
| 46 | useModel() Получить у текущего компонента v-modelпривязанное значение. | const modelValue = useModel() |
| 47 | useTemplateRef() Получить ссылку на элемент в шаблоне. | const templateRef = useTemplateRef('elementId') |
| 48 | useId() Получить уникальный идентификатор. | const uniqueId = useId() |