Encodera

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

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

Оглавление

Загрузка данных: 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Не ждать данных перед показом страницы
serverfalse — загружать только в браузере

Что изменилось в 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.

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

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