ErrorBoundary
Пропы
resetKeys
unknown[] · по умолчанию: —
Когда любое значение меняется (сравнение через Object.is), граница автоматически сбрасывается — та же идея, что и resetKeys у react-error-boundary.
resetOnPropsChange
boolean · по умолчанию: false
Сброс при изменении ссылки на любой проп, а не только resetKeys.
beforeReset
() => void · по умолчанию: —
Вызывается непосредственно перед сбросом (автоматическим или ручным). Не называется onReset — см. примечание ниже.
isolate
boolean · по умолчанию: true
false позволяет ошибке дополнительно распространиться к ближайшему предку <ErrorBoundary>.
maxRetries
number · по умолчанию: без ограничений
По достижении лимита canRetry в слоте fallback становится false.
reporter
ErrorReporter | ErrorReporter[] · по умолчанию: —
Репортер(ы), вызываемые один раз на каждую перехваченную ошибку — см. Адаптеры отчётности.
shouldCatch
(error: CapturedError) => boolean · по умолчанию: —
Верните false, чтобы ошибка прошла через эту границу нетронутой — без изменения состояния, без отчёта, без fallback — как будто границы здесь вообще нет. См. Игнорирование конкретных ошибок.
internalErrorPrefix
string · по умолчанию: '[vue-error-boundary-kit]'
Префикс для страховочного лога, выводимого, когда ваш собственный beforeReset/репортер сам выбрасывает ошибку. Передайте '', чтобы убрать его.
Почему
beforeReset, а неonReset? Этот компонент также генерирует событиеreset, а Vue выводитonResetкак проп-слушатель этого события. Объявленный проп с тем же именем конфликтовал бы с ним:emit()во Vue обращается кprops.onResetнезависимо от того, объявлен ли он «по-настоящему» как проп, — поэтому он срабатывал бы дважды за сброс, причём второй, вызванный через emit, происходит вне собственного try/catch пакета, полностью обходя защиту от рекурсии, если он выбросит ошибку.beforeResetструктурно избегает этого конфликта.
События
error
(error: CapturedError)
Генерируется при каждой перехваченной ошибке, включая всплывшие от дочерней границы с isolate: false.
reset
Генерируется при каждом ручном или автоматическом сбросе.
Слоты
default
Обычный контент.
fallback
{ error, reset, retry, retryCount, canRetry }
reset() также сбрасывает счётчик попыток; retry() увеличивает retryCount и заново пытается отрисовать default, не сбрасывая счётчик.
Доступно через template-ref
error, hasError, retryCount, canRetry, reset(), retry() — то же состояние и методы, что получает слот fallback, но доступные извне (например, элемент управления повтором, расположенный в другом месте интерфейса, или предок, восстанавливающий границу, для которой он не рендерит fallback). Вызов reset()/retry() на границе, не находящейся в состоянии ошибки, — безвредный no-op.
<script setup>
const boundary = ref()
</script>
<template>
<ErrorBoundary ref="boundary">…</ErrorBoundary>
<button @click="boundary?.reset()">Сброс из другого места</button>
</template>Повтор с задержкой (backoff)
retry() срабатывает мгновенно и безусловно — в большинстве случаев этого достаточно, но для временной/сетевой ошибки повтор в момент клика по кнопке обычно снова заканчивается неудачей тем же образом. vue-error-boundary-kit/retry-backoff оборачивает retry() из template-ref в возрастающую задержку:
import { createBackoffRetry } from 'vue-error-boundary-kit/retry-backoff'
const boundary = useTemplateRef('boundary')
const backoff = createBackoffRetry(boundary, { baseDelayMs: 1000, factor: 2, maxDelayMs: 30_000 })<ErrorBoundary ref="boundary">
<template #fallback="{ error }">
<button :disabled="backoff.isPending.value" @click="backoff.retry()">
{{ backoff.isPending.value ? 'Повтор…' : 'Повторить' }}
</button>
</template>
</ErrorBoundary>Задержка вычисляется на основе собственного retryCount границы (baseDelayMs * factor ** retryCount, с ограничением сверху в maxDelayMs), так что каждая следующая попытка ждёт дольше. cancel() отменяет ожидающий повтор. Работает и с ref от <AsyncBoundary> — оба предоставляют одну и ту же форму { retry, retryCount }.
AsyncBoundary
Отдельная точка входа (vue-error-boundary-kit/async-boundary) — не входит в основной бандл, поэтому ничего не стоит, если вы её не импортируете. Объединяет <Suspense> и <ErrorBoundary>, которые сегодня иначе пришлось бы вкладывать друг в друга вручную:
import { AsyncBoundary } from 'vue-error-boundary-kit/async-boundary'<AsyncBoundary :reset-keys="[userId]">
<template #default>
<UserProfile :id="userId" />
<!-- допустим async setup() / асинхронные компоненты -->
</template>
<template #loading>
<Spinner />
</template>
<template #fallback="{ error, retry }">
<ErrorState :message="error.message" @retry="retry" />
</template>
</AsyncBoundary>Это композиция, а не переизобретение: внутри это <ErrorBoundary>, оборачивающий <Suspense>, поэтому он принимает все пропы <ErrorBoundary> (resetKeys, maxRetries, reporter, shouldCatch, …), описанные выше, генерирует те же события error/reset и предоставляет через template-ref те же error/hasError/retryCount/canRetry/reset()/retry() — всё это обрабатывается той же единственной реализацией onErrorCaptured, что уже есть у <ErrorBoundary>. Единственное, что добавляется, — слот loading, отображаемый, пока асинхронные зависимости слота default ещё не разрешились. retry()/reset() перемонтируют слот default, поэтому повторённая асинхронная операция действительно выполняется заново (слот loading появляется снова, пока она выполняется), а не просто повторно показывает устаревшее состояние.