Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Загрузка, ошибки и обновление данных

Запрос может идти долго или закончиться ошибкой, а данные — устареть. Кроме 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 был пустой массив.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.