Encodera

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

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

Оглавление

Загрузка данных из API

Большинство приложений получают данные с сервера через API — адрес, который возвращает JSON. С этого урока курс переходит ко второму примеру — блогу, который читает статьи с тестового API JSONPlaceholder. Загрузка занимает время и может завершиться ошибкой, поэтому компонент должен показывать три состояния: «загружается», «ошибка» и сами данные.

Новый проект

Создайте проект блога так же, как список задач:

npm create vue@latest

Назовите его blog, дополнительные возможности пока не отмечайте. Затем выполните cd blog, npm install, npm run dev.

Загрузка списка статей

Создайте src/components/PostList.vue:

<!-- src/components/PostList.vue -->
<script setup>
import { ref, onMounted } from 'vue'
 
const posts = ref([])
 
onMounted(async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5')
  posts.value = await response.json()
})
</script>
 
<template>
  <ul>
    <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
  </ul>
</template>

Подключите его в src/App.vue — <PostList /> после импорта. Через мгновение после открытия http://localhost:5173 появятся заголовки пяти статей. fetch и async/await работают так же, как в уроках учебника, а Vue перерисует список, когда в posts попадёт массив.

Загрузка и ошибка

Добавим два состояния — loading и error:

<!-- src/components/PostList.vue -->
<script setup>
import { ref, onMounted } from 'vue'
 
const posts = ref([])
const loading = ref(true)
const error = ref(null)
 
onMounted(async () => {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5')
    if (!response.ok) {
      throw new Error(`Сервер ответил ${response.status}`)
    }
    posts.value = await response.json()
  } catch (e) {
    error.value = e.message
  } finally {
    loading.value = false
  }
})
</script>
 
<template>
  <p v-if="loading">Загрузка...</p>
  <p v-else-if="error">Не удалось загрузить статьи: {{ error }}</p>
  <ul v-else>
    <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
  </ul>
</template>

Сначала на странице видно «Загрузка...», затем список. Чтобы проверить ошибку, поменяйте в адресе posts на postz — появится «Не удалось загрузить статьи: Сервер ответил 404».

Состояния компонента

СостояниеloadingerrorЧто видно
Идёт запросtruenull«Загрузка...»
ОшибкаfalseТекст ошибкиСообщение об ошибке
УспехfalsenullСписок статей

Композабл для запросов

Одни и те же три переменные понадобятся на каждой странице блога. Вынесите их в src/composables/useFetch.js:

// src/composables/useFetch.js
import { ref } from 'vue'
 
export function useFetch(url) {
  const data = ref(null)
  const loading = ref(true)
  const error = ref(null)
 
  fetch(url)
    .then((response) => {
      if (!response.ok) throw new Error(`Сервер ответил ${response.status}`)
      return response.json()
    })
    .then((json) => (data.value = json))
    .catch((e) => (error.value = e.message))
    .finally(() => (loading.value = false))
 
  return { data, loading, error }
}

В компоненте остаётся одна строка: const { data: posts, loading, error } = useFetch('https://jsonplaceholder.typicode.com/posts?_limit=5').

Частая ошибка

Сделать асинхронным весь <script setup>, написав await fetch(...) на верхнем уровне. Такой компонент Vue выводит только внутри специального компонента Suspense, а без него страница останется пустой. Загружайте данные в onMounted или через композабл, как в этом уроке.

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

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