Encodera

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

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

Оглавление

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

Задачи обычно хранятся на сервере, и компонент должен получить их после открытия страницы. Alpine понимает асинхронный код: метод init() может быть async, а внутри него работает await. Пока данные идут, пользователю показывают надпись «Загрузка…».

Заглушка вместо сервера

В примерах урока настоящий запрос заменён функцией, которая возвращает промис и отвечает через секунду, — как медленный сервер. В рабочем проекте на её месте будет fetch().

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<script>
  function loadTasks() {
    return new Promise(resolve => {
      setTimeout(() => resolve(['Купить молоко', 'Позвонить Олегу']), 1000);
    });
  }
</script>
 
<ul x-data="{
  tasks: [],
  async init() {
    this.tasks = await loadTasks();
  }
}">
  <template x-for="task in tasks">
    <li x-text="task"></li>
  </template>
</ul>

Через секунду после открытия страницы появляются две задачи. Нажмите «Сбросить» в шапке результата, чтобы увидеть это снова.

Состояние загрузки

Свойство loading показывает, идёт ли запрос. Блок try...finally гарантирует, что оно сбросится в любом случае:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<script>
  function loadTasks() {
    return new Promise(resolve => {
      setTimeout(() => resolve(['Купить молоко', 'Позвонить Олегу']), 1000);
    });
  }
</script>
 
<div x-data="{
  tasks: [],
  loading: true,
  async init() {
    try {
      this.tasks = await loadTasks();
    } finally {
      this.loading = false;
    }
  }
}">
  <p x-show="loading">Загрузка…</p>
  <ul x-show="!loading">
    <template x-for="task in tasks">
      <li x-text="task"></li>
    </template>
  </ul>
</div>

Сначала видна надпись «Загрузка…», через секунду её сменяет список.

Ошибка

Запрос может не удаться. Ошибку ловят в catch и показывают сообщение:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<script>
  function loadTasks() {
    return new Promise((resolve, reject) => {
      setTimeout(() => reject(new Error('Сервер недоступен')), 1000);
    });
  }
</script>
 
<div x-data="{ tasks: [], error: '', async init() {
  try {
    this.tasks = await loadTasks();
  } catch (e) {
    this.error = e.message;
  }
} }">
  <p x-show="error" x-text="'Ошибка: ' + error"></p>
</div>

Через секунду появляется «Ошибка: Сервер недоступен».

С настоящим сервером

В проекте функция загрузки обращается к API через fetch(), как в уроке «Запросы к серверу: fetch» учебника:

// src/api.js
export async function loadTasks() {
  const response = await fetch('/api/tasks');
  if (!response.ok) throw new Error('Ошибка ' + response.status);
  return response.json();
}

Компонент при этом не меняется: он так же ждёт промис через await.

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

Читать данные, которых ещё нет. Пока промис не выполнился, tasks пуст, а selected равен null. Выражение x-text="selected.title" упадёт с ошибкой до прихода ответа. Задавайте начальные значения в x-data — пустой массив, пустую строку — и прячьте зависимые блоки за x-if, пока данных нет.

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

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