# Динамические и асинхронные компоненты

Подразумевается, что уже изучили и разобрались с разделом Основы компонентов. Если нет — прочитайте его сначала.

# Динамические компоненты с keep-alive

Ранее в руководстве атрибут is использовался для переключения между компонентами в интерфейсе с вкладками:

<component :is="currentTabComponent"></component>
1

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

See the Pen Динамические компоненты: без использования keep-alive by Vue (@Vue) on CodePen.

Можно заметить, что выбрав пост, потом переключившись на вкладку Archive, а затем снова вернувшись на Posts, выбранный пост больше не отображается. Это происходит потому, что каждый раз, при переключении на другую вкладку Vue будет создавать новый экземпляр currentTabComponent.

Обычно пересоздание динамических компонентов полезно, но в данном случае хотелось бы чтобы экземпляры компонентов вкладок кэшировались после их создания в первый раз. Для решения этой проблемы динамический компонент можно обернуть в <keep-alive>:

<!-- Неактивные компоненты будут закэшированы! -->
<keep-alive>
  <component :is="currentTabComponent"></component>
</keep-alive>
1
2
3
4

Проверим результат:

See the Pen Динамические компоненты: с использованием keep-alive by Vue (@Vue) on CodePen.

Теперь состояние (выбранный пост) на вкладке Posts будет сохраняться даже тогда, когда она не отрисовывается.

Подробнее о компоненте <keep-alive> можно узнать в справочнике API.

# Асинхронные компоненты

В больших приложениях может потребоваться разделять приложение на меньшие части и загружать компоненты с сервера только когда они необходимы. Для реализации подобного Vue предоставляет метод defineAsyncComponent:

const { createApp, defineAsyncComponent } = Vue

const app = createApp({})

const AsyncComp = defineAsyncComponent(
  () =>
    new Promise((resolve, reject) => {
      resolve({
        template: '<div>Асинхронный компонент!</div>'
      })
    })
)

app.component('async-example', AsyncComp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Как видно, метод принимает функцию-фабрику, которая вернёт Promise. В Promise коллбэк resolve должен быть вызван, когда получено определение компонента с сервера. Кроме того, можно вызвать reject(reason) для обработки неудачной загрузки.

Также можно возвращать Promise из функции-фабрики, поэтому с Webpack 2 или более новой версии и синтаксисом ES2015 можно сделать так:

import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/AsyncComponent.vue')
)

app.component('async-component', AsyncComp)
1
2
3
4
5
6
7

Использовать defineAsyncComponent можно и при локальной регистрации компонента:

import { createApp, defineAsyncComponent } from 'vue'

createApp({
  // ...
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./components/AsyncComponent.vue')
    )
  }
})
1
2
3
4
5
6
7
8
9
10

# Использование с Suspense

Асинхронные компоненты по умолчанию считаются suspensible. Это значит, что при наличии <Suspense> в родительской цепочке, компонент будет рассматриваться как асинхронная зависимость от этого <Suspense>. В этом случае состояние загрузки контролируется <Suspense>, а собственные опции компонента для загрузки, ошибки и задержки таймаута игнорируются.

Асинхронный компонент может отказаться от управления Suspense и всегда использовать собственное состояние для загрузки, с помощью опции suspensible: false.

Список доступных опций можно посмотреть в справочнике API