Загрузка, ошибки и обновление данных
Запрос может идти долго или закончиться ошибкой, а данные — устареть. Кроме data, useFetch и useAsyncData возвращают поля, которые описывают состояние запроса, и функцию для его повтора. С ними страница может показать «Загрузка…», сообщение об ошибке и кнопку «Обновить».
Что возвращает useFetch
| Поле | Что в нём |
|---|---|
data | Ответ сервера |
status | 'idle', 'pending', 'success' или 'error' |
error | Ошибка или undefined |
refresh | Функция, которая повторяет запрос |
clear | Функция, которая сбрасывает данные и ошибку |
Поле pending (true, пока идёт запрос) тоже осталось, но status подробнее.
Ошибка
<!-- app/pages/posts/index.vue -->
<script setup lang="ts">
const { data: posts, error } = await useFetch('/api/posts')
</script>
<template>
<section>
<p v-if="error">Не удалось загрузить статьи: {{ error.message }}</p>
<PostCard v-for="post in posts" v-else :key="post.id" :post="post" />
</section>
</template>Если API вернёт ошибку, вместо списка появится сообщение. Проверить это легко: временно бросьте в server/api/posts.get.ts ошибку throw createError({ statusCode: 500 }).
Ленивая загрузка
С await Nuxt не показывает страницу, пока данные не пришли, поэтому состояние pending почти не видно. Опция lazy: true показывает страницу сразу, а данные дозагружает:
<!-- app/pages/posts/index.vue -->
<script setup lang="ts">
const { data: posts, status } = await useFetch('/api/posts', {
lazy: true
})
</script>
<template>
<section>
<p v-if="status === 'pending'">Загрузка…</p>
<PostCard v-for="post in posts" v-else :key="post.id" :post="post" />
</section>
</template>При переходе на /posts по ссылке страница откроется мгновенно с надписью «Загрузка…», а через мгновение появится список. При первой загрузке сайта данные всё равно придут с сервера в HTML. Есть и сокращение: useLazyFetch('/api/posts').
Обновление по кнопке
<!-- app/pages/posts/index.vue -->
<script setup lang="ts">
const { data: posts, status, refresh } = await useFetch('/api/posts')
</script>
<template>
<section>
<button :disabled="status === 'pending'" @click="refresh()">Обновить</button>
<PostCard v-for="post in posts" :key="post.id" :post="post" />
</section>
</template>Добавьте статью командой curl из урока о теле запроса и нажмите «Обновить» — новая статья появится без перезагрузки страницы. На время запроса кнопка выключена.
Обновление из другого места
У каждого запроса есть ключ. Если задать его явно, обновить данные можно из любого компонента функцией refreshNuxtData:
<!-- app/pages/posts/index.vue -->
<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts', { key: 'post-list' })
</script>Вызов await refreshNuxtData('post-list') в другом компоненте заново загрузит этот список.
Частая ошибка
Включить lazy: true и обращаться к данным сразу в скрипте: posts.value.map(...). При ленивой загрузке в первый момент данных ещё нет, posts.value равно undefined, и код падает. С ленивыми запросами всегда проверяйте данные или задайте опцию default: () => [], чтобы до ответа в data был пустой массив.