..

🔥 Optimistic updates

Читать в Telegram

Некоторые действия пользователя в приложениях порой требуют мгновенной реакции в UI. Добавление товаров в Избранное, лайки в соц. сетях, отметка задачи в TODO-листе как выполненной - все это делается в моменте. Пользователь не хочет ждать, пока мы сходим на бэк и только после все манипуляций и с задержкой обновим ему интерфейс.

В реализации задачи мгновенных обновлений нам может помочь паттерн Optimistic updates. Мы сразу отображаем в UI результат действия пользователя, не дожидаясь ответа от сервера, как будто он точно будет успешным. А если вдруг сервер вернул ошибку - откатываем произошедшие изменения. Реализация Optimistic updates есть во многих приложениях, решение существует уже давно. Откройте какой-нибудь VK или другую социальную сеть и поставьте лайк на пост - сердечко закрасится моментально.

Дополнительно что-то делать на UI, как правило, не нужно. Во многих случаях достаточно просто дописать логику обработки таких действий в блоке или где-то еще.

Мы эмитим состояние с новым списком избранного сразу же, как только пришел эвент на добавление товара в него:

Future<void> _addToFavorites(FavoritesAddRequest event,
    Emitter<FavoritesState> emit,) async {
  final product = event.product;

  // Добавляем товар в избранное в состоянии до запроса в сеть.
  // В реализации без Optimistic updates этого шага не было бы.
  emit(
    state.copyWith(
      favorites: [
        ...state.favorites,
        product.id,
      ],
    ),
  );

  final result = await repository.addToFavorites(product.id);

  // Поскольку ранее мы уже обновили наше состояние, нужно только проверить ошибку в запросе.
  // Если она есть, то откатываем состояние, если нет - оставляем все как есть.
  if (result.error != null) {
    final currentFavorites = state.favorites.toList();
    currentFavorites.remove(product.id);

    emit(
      state.copyWith(
        favorites: currentFavorites,
        error: 'Не удалось добавить ${product.title} в Избранное',
      ),
    );
  }
}

❗️ Код выше - это базовая реализация Optimistic updates. Она не включает в себя обработку множества запросов в один момент времени, работу с оффлайном и другие корнер-кейсы. Но ее достаточно для начала, и доработки будут строиться уже вокруг начальной реализации и потребностей продукта.

Важно учитывать так же несколько моментов:

Откат. Обязательная часть паттерна. Без него это не фича, а скорее баг. Пользователю важна не только скорость работы приложения, но и его целостность. Никому не понравится видеть добавление товара в Избранное, а при перезаходе в приложение наблюдать его отсутствие.

Паттерн не для всех операций. Мы не можем взять и просто так перевести оплату заказа, подтверждение данных, отправку отчетов. Сложные операции лучше проводить с ожиданием ответа сервера.

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