Использование Ember.PromiseProxyMixin в теме

Недавно в ядро Discourse в модулях Ember был добавлен Ember.PromiseProxyMixin.

Это очень полезная миксин-библиотека Ember, которая позволяет выполнять асинхронные запросы и удобно работать с промисами внутри компонентов Ember. Представьте её как React Suspense, но для Ember. Потенциал для разработки тем и плагинов в Discourse огромен.

Вот официальная документация Ember по Ember.PromiseProxyMixin.

А здесь вы можете найти подробный пример использования Ember.PromiseProxyMixin (не связанный с Discourse).

Я приведу простой пример того, как эту миксин можно использовать внутри темы Discourse. Допустим, по какой-то причине в компоненте topic-list-item вы хотите стилизовать аватар автора, если он является сотрудником: у аватара должна быть другая рамка.

Где-то в файле topic-list-item.js(.es6) вам потребуется:

  • Импортировать EmberObject и PromiseProxyMixin и расширить EmberObject с помощью PromiseProxyMixin:
import EmberObject from "@ember/object";
import PromiseProxyMixin from "@ember/object/promise-proxy-mixin";

const PromiseObject = EmberObject.extend(PromiseProxyMixin);

// Вы можете использовать пользовательскую функцию мемоизации, чтобы предотвратить множественные запросы для одних и тех же пользователей
const getUser = memoize(username => ajax(`/u/${username}`).then(data => data));
  • Затем вам нужно создать следующие вычисляемые свойства:
  // Вычисляемый промис
  @discourseComputed("topic")
  posterPromise(topic) {
    const { user } = topic.posters[0];
    return getUser(user.username);
  },

  // Это вычисляемое свойство оборачивает промис в `PromiseObject`
  @discourseComputed("posterPromise")
  posterProxy() {
    const promise = this.get("posterPromise");
    return promise && PromiseObject.create({ promise });
  },

  posterData: reads("posterProxy.content.user"),

  @discourseComputed("posterData")
  isStaff() {
    const posterData = this.get("posterData");
    if (!posterData) return false;
    const { groups = [] } = posterData;
    // Чтобы проверить, является ли пользователь сотрудником, нужно убедиться,
    // что он состоит в группе сотрудников
    return groups.some(({ name }) => name === "staff");
  }

А в шаблоне topic-list-item.hb(r|s) у вас будет что-то вроде этого:

  {{#if posterProxy.isFulfilled}}
    {{#if isStaff}}
      // выполните вашу кастомизацию
    {{/if}}
  {{/if}}

Вы также можете использовать isPending, чтобы, например, показать индикатор загрузки.

Надеюсь, этот не самый полезный пример поможет вам разобраться, как работает миксин, и, возможно, подскажет, как вы сможете использовать его в разработке своих тем или плагинов.

:wave:

4 лайка

Привет, @zcuric,

спасибо за эту отличную статью и начальный PR. Здесь есть что исследовать как в плагинах и темах, так и в самой кодовой базе Discourse. Посмотрим, как применить этот паттерн и, возможно, упростить его в будущем :+1:

5 лайков