Загрузка данных: useFetch
useFetch — composable для загрузки данных в компоненте. При первом открытии страницы он выполняет запрос на сервере, вставляет результат в HTML и передаёт данные в браузер. Браузеру не нужно повторять запрос, а пользователь сразу видит готовую страницу.
Список статей с сервера
Замените массив в app/pages/posts/index.vue запросом к API:
<!-- app/pages/posts/index.vue -->
<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts')
</script>
<template>
<section>
<h2>Статьи</h2>
<PostCard v-for="post in posts" :key="post.id" :post="post" />
</section>
</template>useFetch возвращает объект; поле data — это ref с ответом сервера, здесь он переименован в posts. await нужен, чтобы сервер дождался данных, прежде чем отправлять HTML. Откройте /posts — список придёт из server/api/posts.get.ts. Откройте исходный код страницы в браузере: заголовки статей уже есть в HTML.
Типы без описания
Nuxt знает, что возвращает server/api/posts.get.ts, и сам выводит тип posts. Редактор подскажет поля id, title и text, а опечатка post.titel будет подчёркнута.
Страница статьи
На странице app/pages/posts/[id].vue адрес запроса зависит от параметра:
<!-- app/pages/posts/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: post } = await useFetch(() => `/api/posts/${route.params.id}`)
</script>
<template>
<article v-if="post">
<h2>{{ post.title }}</h2>
<p>{{ post.text }}</p>
</article>
</template>Адрес передан функцией: при переходе с /posts/1 на /posts/2 функция вернёт новый адрес, и useFetch загрузит другую статью. Адрес /posts/1 покажет первую статью из хранилища.
Параметры запроса
Строку поиска передают опцией query. Если в неё положить ref, запрос повторится при каждом изменении:
<!-- app/pages/posts/index.vue -->
<script setup lang="ts">
const search = ref('')
const { data: posts } = await useFetch('/api/posts', {
query: { search }
})
</script>
<template>
<section>
<input v-model="search" placeholder="Поиск по заголовкам">
<PostCard v-for="post in posts" :key="post.id" :post="post" />
</section>
</template>Начните вводить «nuxt» — список сузится: useFetch отправит запрос /api/posts?search=nuxt.
Основные опции
| Опция | Что делает |
|---|---|
query | Параметры после ? |
method | Метод HTTP, по умолчанию GET |
pick | Оставить в данных только указанные поля |
default | Значение data, пока ответа нет |
lazy | Не ждать данных перед показом страницы |
server | false — загружать только в браузере |
Что изменилось в Nuxt 4
В Nuxt 4 data до получения ответа или после ошибки равна undefined (в Nuxt 3 была null). Кроме того, data по умолчанию «неглубоко» реактивна: замена значения целиком отслеживается, а изменение поля внутри объекта — нет.
Частая ошибка
Писать posts.value.length в <script setup> без проверки. Если сервер ответил ошибкой, data будет undefined, и страница упадёт с Cannot read properties of undefined. В скрипте используйте posts.value?.length, а в шаблоне выводите данные внутри v-if.