Оптимистичные обновления

Одной из наиболее мощных концепций, доступных разработчикам через библиотеку HTMX, является возможность оптимистичных обновлений. Этот подход позволяет создавать пользовательские интерфейсы, которые мгновенно реагируют на действия пользователя, улучшая восприятие производительности и снижая задержки взаимодействия. В рамках HTMX оптимистичные обновления дают возможность предусматривать результат действия пользователя, прежде чем сервер вернёт окончательное подтверждение. Это особенно полезно для динамических интерфейсов с асинхронными запросами, где важна мгновенная обратная связь.

Что такое оптимистичные обновления?

Оптимистичное обновление — это техника, при которой предполагаемый результат операции отображается на странице сразу после её инициации, не дожидаясь ответа от сервера. В случае успешного выполнения запроса на сервере, отображаемые данные остаются без изменений. Однако если сервер возвращает ошибку, отображение данных будет откатано в исходное состояние.

HTMX реализует этот подход через атрибуты hx-boost и hx-swap, а также позволяет вручную управлять состоянием элементов с помощью событий и хранилища состояний. Эта возможность позволяет сделать веб-приложение более отзывчивым, что особенно важно для взаимодействия с сервером, где скорость ответа может варьироваться.

Как это работает?

  1. Предположения о результате: Когда пользователь совершает действие, например, нажимает кнопку или отправляет форму, HTMX позволяет мгновенно обновить часть интерфейса, предполагая, что сервер вернёт успешный ответ.
  2. Обратная связь: В момент действия пользователю сразу показывается обновлённый интерфейс — например, удаление элемента из списка или изменение его состояния.
  3. Откат: Если сервер сообщает о ошибке или возвращает неудачный ответ, интерфейс откатывается к прежнему состоянию, что может быть сделано с помощью обработки ошибки.

Основное преимущество этого подхода — значительное улучшение восприятия работы приложения. Пользователи видят результат действий сразу, а не ждут, пока запрос к серверу будет обработан.

Использование атрибутов для оптимистичных обновлений

HTMX предоставляет несколько ключевых атрибутов для реализации оптимистичных обновлений.

hx-boost

Атрибут hx-boost используется для ускорения действий пользователя, связанных с переходами по страницам. При его применении HTMX автоматически перехватывает обычные ссылки и заменяет их асинхронным запросом. В случае с оптимистичными обновлениями, это позволяет моментально обновить страницу с учётом предполагаемых изменений, ускоряя переходы между различными частями интерфейса.

<a hx-boost="true" href="/new-content">Перейти к новому контенту</a>

Этот атрибут можно использовать, например, для ускорения навигации, где изменения интерфейса предполагаются сразу после клика по ссылке, а не дожидаясь полного ответа от сервера.

hx-swap

Атрибут hx-swap позволяет управлять способом обновления контента на странице. При использовании оптимистичных обновлений можно заранее предусмотреть, как будет выглядеть обновлённая часть страницы после завершения действия.

<div id="post-list" hx-get="/posts" hx-swap="outerHTML">
  <!-- Список постов будет обновлён, а не перерисован целиком -->
</div>

Использование hx-swap="outerHTML" позволяет заменить содержимое элемента сразу, на основе предварительно предполагаемых изменений.

hx-on

Атрибут hx-on позволяет привязывать события, которые могут инициировать обновление данных или взаимодействие с сервером. Это удобно, например, для обработки ошибок или обработки откатов в случае неверных ответов.

<button hx-post="/submit" hx-on="htmx:beforeRequest:cancel">Отправить</button>

В данном примере кнопка отправляет запрос, но в случае ошибки от сервера можно отменить действия и вернуть страницу в прежнее состояние.

Пример реализации

Для более глубокого понимания того, как работают оптимистичные обновления, рассмотрим пример с удалением поста.

  1. HTML-разметка:
<div id="post-123" hx-get="/delete-post/123" hx-swap="outerHTML" hx-trigger="click">
  <button>Удалить пост</button>
</div>
  1. JavaScript-логика для обработки ошибки:
document.body.addEventListener('htmx:beforeSwap', function (event) {
  if (event.target.id === 'post-123' && event.detail.xhr.status !== 200) {
    alert('Ошибка при удалении поста');
  }
});
  1. Поведение:

    • При нажатии на кнопку отправляется запрос на удаление поста.
    • В случае успешного выполнения запроса, элемент с постом исчезает, как если бы пост был удалён.
    • Если сервер возвращает ошибку, элемент остаётся на месте, и показывается сообщение об ошибке.

Управление состоянием с помощью JavaScript

Для более сложных приложений, где требуется точный контроль над состоянием интерфейса, HTMX предоставляет методы для ручного управления обновлениями и откатами.

Для этого можно использовать событие htmx:beforeRequest или htmx:afterRequest для изменения состояния DOM или интерфейса.

document.body.addEventListener('htmx:beforeRequest', function (event) {
  if (event.target.id === 'post-123') {
    // Мгновенное удаление поста до ответа от сервера
    event.target.innerHTML = 'Удаление...';
  }
});

В этом случае пользователь сразу видит, что пост удаляется, ещё до получения ответа от сервера.

Использование кэширования для ускорения оптимистичных обновлений

Кэширование на стороне клиента позволяет ускорить процесс и сделать его более эффективным. Например, при оптимистичном обновлении можно хранить состояние данных в localStorage или sessionStorage, чтобы при откате к первоначальному состоянию данные не были потеряны.

localStorage.setItem('deletedPostId', '123');

Этот подход полезен, когда необходимо учитывать состояние после ошибок, а также для синхронизации с другими частями приложения.

Заключение

Оптимистичные обновления предоставляют разработчикам мощный инструмент для улучшения взаимодействия с пользователем в динамических веб-приложениях. Используя возможности HTMX, можно сделать интерфейс максимально отзывчивым и снизить время ожидания ответа от сервера. Этот подход особенно полезен для уменьшения ощущаемой задержки, улучшения пользовательского опыта и создания современных интерфейсов, которые реагируют на действия пользователя в реальном времени.