Ember.js-さようならMVC(部1)

記事Ember.js-Goodbye MVC(パート1)の翻訳に注目してください。



EmberConf 2015カンファレンスで、Yehuda KatzとTom Daleは、Ember 2に対するいくつかの変更が間もなく行われることを発表しました。 廃止されたコントローラーを認識して削除することができます。 EmberとSproutcoreは常にMVCクライアントフレームワークであったため、これは多くのEmberユーザーを驚かせました。



さようならMVC



新しいEmber 2の規約と変更の多くが、 ReactFlux (Reactアプリケーションでのデータフローのパターン)の直接の影響下にあることは秘密ではありません。 Fluxが「単方向データフロー」と呼ぶものは、Emberは「データダウン、アクションアップ」パターン(DDAU)です。



従来のクライアントMVCパターンの代わりに、DDAUは単一のデータストリームを提供するため(一方の方向)、アプリケーションコードの認識とパフォーマンスの向上が容易になります。 MVCの基本的な問題は、アプリケーションが成長し、より複雑になるにつれて明らかになります。 カスケード更新と明白でない依存関係は、混乱と混乱を招きます。 あるオブジェクトを更新すると、別のオブジェクトが変更され、その結果、次のプロセスが開始され、最終的にアプリケーションサポートが真の「悪夢」に変わります。



画像 Ember 2.0データがダウン、アクションがアップ



DDAUパターンでは、データストリームは単方向であり、双方向のバインディングはありません。 アプリケーションのさまざまな部分は、大部分が一貫性がなく理解しやすいままです。 これは、オブジェクトの変更のソースが常にわかることを意味します。 関数型プログラミングとオブザーバー効果に関する私の記事を読むと、サードパーティの効果からコンポーネントの独立性を維持することが非常に重要である理由を理解できます。



十数個のマイクロライブラリと機能を実装する最良の方法を意味のない検索で間に合わせのフレームワークを構築する時間を無駄にする代わりに、Emberを使用する必要があります。 DDAUパターンとGlimmer視覚化エンジンとの組み合わせで、Ember開発者は最初はパフォーマンスと効率の両方を自由に利用できます。



DDAU用のアプリケーションの準備



ルーティング可能なコンポーネントが表示されると、コントローラーは廃止され、フレームワークから削除されます。 コントローラーとビューは常に新しいEmberユーザーを混乱させており、「コンポーネントの役割を果たしていたケースの80%で」(このビデオではYehudaとTomから詳細を学ぶことができます)。



Glimmerが必要と判断した場合、コンポーネントはシングルトンではないため、分解され、最適化された形式で再び表示されます。 しかし、コントローラーが削除された場合、状態を保存する方法はありますか?



たとえば、コントローラにいくつかのプロパティがあります。 アプリケーションに保存したい状態を保持します。 Ember 2でこれを行うには、コントローラーのこのプロパティを削除し、「サービス対応コンポーネント」を代わりに配置します。 このサービスは、単一のコンポーネントの状態を保存し、必要な場合にのみ直接入力します。 サービスは多くの機能を提供するため、一部の開発者はそれらを悪用する場合があります。 記事の最後でサービスについて説明します。



サービス対応コンポーネントの実装



次の例では、今日のサービスと単方向バインディングの使用方法を示します。 以下のテキストを読んで、このデモを並行して使用できます。



この小さなアプリケーションは、動物を選択できるいくつかのチェックボックスで構成されています。 このサンプルは異なるルートに保存し、ルートに戻るときに状態を復元する必要があります。 選択したアイテムの状態を保存し、ルーティング可能なコンポーネントに挿入する単純なサービスを定義する必要があります。



ルートテンプレートでは、 ヘルパーを介して入力したサービスステータスを表示するだけです。



{{! animals/index.hbs }} <div class="row"> <div class="col-md-3"> <h2>Select Animals</h2> {{checkbox-group group=animals selectedItems=checkboxGroup.selectedItems check=(action "check") }} </div> <div class="col-md-9"> <h3>Selected Animals</h3> <table class="table table-bordered"> <thead> <tr> <th>ID</th> <th>Species</th> <th>Name</th> </tr> </thead> <tbody> {{#each checkboxGroup.selectedItems as |animal|}} <tr> <td>{{animal.id}}</td> <td>{{animal.species}}</td> <td>{{animal.name}}</td> </tr> {{/each}} </tbody> </table> </div> </div>
      
      





コントローラーまたはルーティングされたコンポーネントで、サービスに入り、マークされた動物を処理するためのアクションを定義します。 その後、サービス状態のセットがコンポーネントに渡され、可能な限りクリーンに保たれます。 コンポーネントにサービスを入力するだけでもかまいませんが、上記の方法を使用すると、プロセスを明確にし、コンポーネントをサービスから分離できます。



 // animals/controller.js import Ember from 'ember'; const { inject: { service }, Controller } = Ember; const OPERATION_MAP = { true: 'addObject', false: 'removeObject' }; export default Controller.extend({ checkboxGroup: service(), // In the future, actions will be defined in the route and passed into the // routable component as `attributes`. actions: { check(group, item, isChecked) { return group[OPERATION_MAP[isChecked]](item); } } });
      
      





前述のように、サービス自体は単純です。 後でより複雑な動作を定義できますが、ここでは状態の基礎となる永続性は単なるJavaScriptの配列です。



 // checkbox-group/service.js import Ember from 'ember'; const { Service } = Ember; export default Service.extend({ init() { this._super(...arguments); this.selectedItems = []; } });
      
      





この例では単純な動作を使用しているため、コンポーネントのサブクラスを定義する必要はありません。 チェックアクションはルーティングされたコンポーネント/コントローラーから渡されるため、コンポーネントテンプレートでクローズアクションを使用することは、 sendActionsをvoidにキャストしないことを意味します。



コンポーネントテンプレートでは、構成可能な小さなヘルパーを使用します。 これらのヘルパーは、本質的に単純なJavaScript関数です。 そして、それらは値を返すので、それらをHandlebarsの部分式として使用できます。そこで、計算プロパティを一度定義できます。



containsヘルパーは最初はEmberの一部ではありませんが、関数自体は1行のコードです。 ヘルパーがアプリケーションに追加する便利な追加機能がいくつかあります。 たとえば、私自身がほとんどすべてのアプリケーションで使用しているember-truth-helpersの追加。



 {{! checkbox-group/template.hbs }} {{#each group as |item|}} <div class="checkbox"> <label for={{concat "item-" item.id}}> {{one-way-input id=(concat "item-" item.id) class="checkbox" type="checkbox" checked=(contains selectedItems item) update=(action this.attrs.check selectedItems item) }} {{item.name}} <span class="label label-default">{{item.species}}</span> </label> </div> {{/each}}
      
      





前の記事で述べたように、 ember-one-way-inputアドオンは、現在、一方向バインディングを使用する簡単な方法です。



この簡単な例が、ヘルパー、クローズドアクション、コンポーネント、一方向バインディングなど、お気に入りのEmberの機能を使用して、メンテナンスが容易で効率的なアプリケーションを作成する方法を示すことを願っています。



サービス注意



ここでは、すべてがよく知られている表現のとおりです。「強度が大きければ大きいほど、責任は大きくなります。」 Emberのサービスはシングルトーンであるため、いくつかのサービスを作成してどこにでも入力したいという欲求に誘惑されます。



グローバルオブジェクトとして使用するためだけにサービスを作成する場合、依存関係が明白にならず(これが悪いことが既にわかっている)、アプリケーションの各部分が密接に関連するため、一般的にコードは「青く」なります。 代わりに、インターフェイスを介してデータとアクションを公開し、コードを分離して明確に保ちます。 強さと責任の原則を覚えて、絶対に必要な場合にのみサービスを使用してください!



いつサービスを使用しますか?



私は、シングルトーンの使用に関するStack Overflow回答が好きです。 実際、アプリケーション全体でインスタンスを1つしか使用できない場合にのみ使用してください。 たとえば、オンラインストアのショッピングカート、アクティビティフィード、またはインスタントメッセージングは、サービスを使用するのに最適な候補です。






記事の翻訳-Ember.js-さようならMVC(部1)



記事を提供してくれたサイトemjs.ruの翻訳者と参加者に感謝します。



All Articles