Suspense
Вакансии vuejobs.com
Экспериментальная возможность
<Suspense>
является экспериментальной функцией. Не гарантируется, что она достигнет стабильного состояния, и API может измениться до того, как это произойдет.
<Suspense>
- это встроенный компонент для организации асинхронных зависимостей в дереве компонентов. Он может отображать состояние загрузки в ожидании разрешения нескольких вложенных асинхронных зависимостей в дереве компонентов.
Асинхронные зависимости
Чтобы пояснить, какую проблему пытается решить <Suspense>
и как она взаимодействует с этими асинхронными зависимостями, представим себе иерархию компонентов следующим образом:
<Suspense>
└─ <Dashboard>
├─ <Profile>
│ └─ <FriendStatus> (компонент с async setup())
└─ <Content>
├─ <ActivityFeed> (асинхронный компонент)
└─ <Stats> (асинхронный компонент)
В дереве компонентов есть несколько вложенных компонентов, рендеринг которых зависит от того, какой асинхронный ресурс должен быть разрешен первым. Без <Suspense>
каждый из них должен будет обрабатывать свои собственные состояния загрузки/ошибки и загрузки. В худшем случае мы можем увидеть на странице три загрузочных спиннера, содержимое которых будет отображаться в разное время.
Компонент <Suspense>
дает нам возможность отображать состояния загрузки/ошибки верхнего уровня, пока мы ожидаем разрешения этих вложенных асинхронных зависимостей.
Существует два типа асинхронных зависимостей, от которых может ждать <Suspense>
:
Компоненты с асинхронным хуком
setup()
. Сюда относятся компоненты, использующие<script setup>
с выражениямиawait
верхнего уровня.
async setup()
Хук setup()
компонента Composition API может быть асинхронным:
js
export default {
async setup() {
const res = await fetch(...)
const posts = await res.json()
return {
posts
}
}
}
При использовании <script setup>
наличие выражений await
верхнего уровня автоматически делает компонент асинхронной зависимостью:
vue
<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>
<template>
{{ posts }}
</template>
Асинхронные компоненты
Асинхронные компоненты по умолчанию являются "приостанавливаемыми". Это означает, что если в родительской цепочке у него есть <Suspense>
, то он будет рассматриваться как async-зависимость от этого <Suspense>
. В этом случае состояние загрузки будет контролироваться <Suspense>
, а собственные параметры загрузки, ошибки, задержки и таймаута компонента будут игнорироваться.
Асинхронные компоненты могут отказаться от управления Suspense
и позволить компоненту всегда контролировать собственное состояние загрузки, указав в параметрах suspensible: false
.
Состояние загрузки
Компонент <Suspense>
имеет два слота: #default
и #fallback
. Оба слота допускают только один непосредственный дочерний узел. Узел в слоте по умолчанию показывается, если это возможно. Если это невозможно, то вместо него будет показан узел в слоте fallback.
template
<Suspense>
<!-- компонент с вложенными асинхронными зависимостями -->
<Dashboard />
<!-- загрузка состояния через #fallback слот -->
<template #fallback>
Загрузка...
</template>
</Suspense>
При первом рендеринге <Suspense>
выводит содержимое слота по умолчанию в память. Если во время этого процесса будут обнаружены какие-либо асинхронные зависимости, то он перейдет в состояние ожидания. Во время ожидания будет отображаться содержимое резервного слота. Когда все асинхронные зависимости будут разрешены, <Suspense>
перейдет в состояние разрешения и будет отображено содержимое разрешенного слота по умолчанию.
Если при начальном рендеринге не было обнаружено асинхронных зависимостей, то <Suspense>
сразу перейдет в состояние resolved.
Находясь в разрешенном состоянии, <Suspense>
вернется в состояние ожидания только в случае замены корневого узла слота #default
. Новые асинхронные зависимости, вложенные глубже в дерево, не приведут к переходу <Suspense>
в состояние ожидания.
Когда происходит возврат, содержимое резервной копии не будет отображаться немедленно. Вместо этого <Suspense>
будет отображать предыдущее содержимое #default
, ожидая разрешения нового содержимого и его асинхронных зависимостей. Такое поведение может быть настроено с помощью параметра timeout
: <Suspense>
будет переключаться на резервное содержимое, если для отображения нового содержимого по умолчанию требуется больше времени, чем timeout
. При значении timeout
, равном 0
, резервное содержимое будет отображаться сразу после замены стандартного содержимого.
События
Компонент <Suspense>
генерирует 3 события: pending
, resolve
и fallback
. Событие pending
возникает при переходе в состояние ожидания. Событие resolve
возникает при завершении разрешения нового содержимого в слоте по умолчанию
. Событие fallback
происходит, когда отображается содержимое слота fallback
.
Эти события могут быть использованы, например, для отображения индикатора загрузки перед старым DOM во время загрузки новых компонентов.
Обработка ошибок
В настоящее время <Suspense>
не предоставляет возможности обработки ошибок через сам компонент, однако вы можете использовать опцию errorCaptured
или хук onErrorCaptured()
для перехвата и обработки ассинхронных ошибок в родительском компоненте <Suspense>
.
Комбинирование с другими компонентами
Часто требуется использовать <Suspense>
в сочетании с компонентами <Transition>
и <KeepAlive>
. Порядок вложения этих компонентов важен для обеспечения их корректной работы.
Кроме того, эти компоненты часто используются совместно с компонентом <RouterView>
из Vue Router.
В следующем примере показано, как вложить эти компоненты так, чтобы все они работали как положено. Для получения более простых комбинаций можно удалить ненужные компоненты:
template
<RouterView v-slot="{ Component }">
<template v-if="Component">
<Transition mode="out-in">
<KeepAlive>
<Suspense>
<!-- основное содержание -->
<component :is="Component"></component>
<!-- состояние загрузки -->
<template #fallback>
Загрузка...
</template>
</Suspense>
</KeepAlive>
</Transition>
</template>
</RouterView>
В Vue Router встроена поддержка ленивой загрузки компонентов с помощью динамического импорта. Они отличаются от асинхронных компонентов и в настоящее время не вызывают <Suspense>
. Однако они могут иметь в качестве потомков асинхронные компоненты, которые могут вызывать <Suspense>
обычным способом.