# テーマで Ember.PromiseProxyMixin を使用する

**URL:** https://meta.discourse.org/t/use-ember-promiseproxymixin-in-a-theme/147231
**Category:** Developers
**Tags:** how-to, theme-guides
**Created:** [2020 年 4 月 8 日午前 8:21 UTC](https://meta.discourse.org/t/use-ember-promiseproxymixin-in-a-theme/147231 "2020-04-08T08:21:39Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![zcuric](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zcuric/32/292837_2.png) [@zcuric](https://meta.discourse.org/u/zcuric)
#### Post date: [2020 年 4 月 8 日午前 8:21 UTC](https://meta.discourse.org/t/use-ember-promiseproxymixin-in-a-theme/147231/1 "2020-04-08T08:21:39Z")

</div>

最近、Discourse コア内の Ember モジュールに `Ember.PromiseProxyMixin` が追加されました。

> <https://github.com/discourse/discourse/pull/9312>
>
> \### This PR: 
> \- \[x\] Adds \[Ember.PromiseProxyMixin \](https://api.emberjs.com/emb…er/3.12/classes/PromiseProxyMixin) to ember modules. Reason for this is to make components work with async computed props. Good example can be found \[here\](https://lolma.us/en/blog/promise-proxy-mixin/). 
> 
> This could be useful in discourse theme development if you need some data that is not available at the moment. For example: for some reason you want to decorate poster avatar with border in topic list if the poster is a staff member. To find out if user is staff member you'll need to send a request to \`/u\` endpoint, and if true react accordingly to that condition in template.

これは非常に便利な Ember ミックスインで、非同期リクエストを実行し、Ember コンポーネント内で Promise を簡単に扱うことを可能にします。Ember 版の [React Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html) と考えてください。Discourse におけるテーマやプラグイン開発の可能性は非常に大きいです。

以下は、[Ember の公式ドキュメント（Ember.PromiseProxyMixin について）](https://api.emberjs.com/ember/3.12/classes/PromiseProxyMixin)です。

また、[Ember.PromiseProxyMixin の使い方を詳しく解説した、Discourse 以外の例](https://lolma.us/en/blog/promise-proxy-mixin/)もご覧ください。

ここでは、Discourse テーマ内でこのミックスインをどのように使えるか、簡単な例を示します。例えば、何らかの理由で `topic-list-item` コンポーネント内で、投稿者がスタッフメンバーの場合にアバターをスタイリングしたいとします。その場合、アバターには異なるボーダーを付ける必要があります。

`topic-list-item.js(.es6)` のどこかで以下の処理を行う必要があります：

- `EmberObject` と `PromiseProxyMixin` をインポートし、`EmberObject` を `PromiseProxyMixin` で拡張します。

```js
import EmberObject from "@ember/object";
import PromiseProxyMixin from "@ember/object/promise-proxy-mixin";

const PromiseObject = EmberObject.extend(PromiseProxyMixin);

// 同じユーザーへの重複リクエストを防ぐために、カスタム memoize 関数を使用できます
const getUser = memoize(username => ajax(`/u/${username}`).then(data => data));

```

- 次に、以下の計算プロパティを作成します。

```js
  // 計算された Promise
  @discourseComputed("topic")
  posterPromise(topic) {
    const { user } = topic.posters[0];
    return getUser(user.username);
  },

  // この計算プロパティは Promise を `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)` には以下のようなコードが書かれます：

```handlebars
  {{#if posterProxy.isFulfilled}}
    {{#if isStaff}}
      // カスタマイズ処理を実行
    {{/if}}
  {{/if}}

```

`isPending` を活用して、ローダーを表示することも可能です。

このあまり役に立たない例かもしれませんが、ミックスインの仕組みを理解する助けになれば幸いです。もしかすると、テーマやプラグイン開発でどのように活用できるかを見つけるきっかけになるかもしれません。

👋

---

<div class="post-metadata">

### Author: ![j.jaffeux](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/j.jaffeux/32/60297_2.png) [@j.jaffeux](https://meta.discourse.org/u/j.jaffeux)
#### Post date: [2020 年 4 月 8 日午前 10:01 UTC](https://meta.discourse.org/t/use-ember-promiseproxymixin-in-a-theme/147231/2 "2020-04-08T10:01:08Z")

</div>

@zcuric さん、こんにちは

とても素晴らしい記事と最初の PR をありがとうございます。プラグインやテーマ、そして Discourse のコードベースにおいても、ここで探求すべき点は確かにあります。このパターンをどのように適用し、将来的にさらにシンプルにするか検討してまいります 👍
