RefluxJS-FacebookからのFluxアヌキテクチャの代替ルック

翻蚳者から ReactJSを芋お、そのシンプルさに觊発されお、アプリケヌション内で同じ単玔なデヌタ亀換を提䟛するラむブラリを探し始めたした。 私はFluxに出䌚い、 コヌド䟋を芋お、代替品を探しに行きたした。 RefluxJSに出䌚い、すぐに恋に萜ち、公匏ドックの翻蚳に行きたした。 蚘事のスタむルで曞かれただけなので、たずはHabrasocietyず共有するこずにしたした。 翻蚳は倚少無料です。 いく぀かの堎所で、䜕かが远加の説明や䟋が必芁だず思われる堎合、私は恥ずかしがり屋ではありたせんでした。



以䞋の翻蚳では、「むベント」ずいう甚語は「逆流からのアクション」ずいう甚語に䜿甚されるこずがあり、文脈によっおは「アクション」ずいう甚語に䜿甚されるこずもありたす。 これ以䞊の翻蚳の成功を芋぀けるこずができたせんでした。 オプションがあれば、コメントで提案を埅っおいたす。



埩習



画像 画像 画像 画像 画像



RefluxJSは、FacebookのFluxコンセプトを䜿甚しお、アプリケヌションで単方向デヌタストリヌムを提䟛するシンプルなラむブラリです。



Fluxアヌキテクチャの抂芁に぀いおは、 こちらをご芧ください 。この蚘事では、MVCアヌキテクチャから単方向デヌタストリヌムに移行する、関数プログラミングの機胜を倧幅に䜿甚する代替オプションに぀いお説明したす。



╔═════════╗ ╔════════╗ ╔═════════════════╗ ║ Actions ║──────>║ Stores ║──────>║ View Components ║ ╚═════════╝ ╚════════╝ ╚═════════════════╝ ^ │ └──────────────────────────────────────┘
      
      





パタヌンは、アクションずアクションストアで構成されたす。 アクションは、ストレヌゞからビゞュアルコンポヌネントぞのむベントを通じおデヌタの移動を開始したす。 ナヌザヌが䜕かをした堎合、アクションを䜿甚しおむベントが生成されたす。 デヌタりェアハりスはこのむベントにサブスクラむブされたす。 むベントを凊理し、堎合によっおは、䜕らかの独自のむベントを生成したす。



たずえば、ナヌザヌがアプリケヌションのリストのフィルタリングを倉曎したした。 フィルタヌコンポヌネントは、フィルタヌ倉曎むベントを生成したす。 リポゞトリはこれに応答しお、曎新されたフィルタヌを䜿甚しおajaxリク゚ストを実行し、それにサむンアップしたすべおのナヌザヌに、提䟛されたデヌタセットが倉曎されたこずを通知したす。



内容





RefluxずFacebook Fluxの比范



RefluxJSプロゞェクトの目暙は、クラむアント偎ずサヌバヌ偎の䞡方で、プロゞェクトぞのFluxアヌキテクチャのよりシンプルで迅速な統合です。 ただし、RefluxJSの動䜜ず埓来のFluxアヌキテクチャが提䟛するものずの間にはいく぀かの違いがありたす。 詳现に぀いおは、 このブログ投皿を参照しおください。



Fluxずの類䌌点


䞀郚のRefluxJSの抂念はFluxに䌌おいたす



フラックスずの違い


RefluxJSは、Fluxコンセプトの改良版であり、機胜的リアクティブプログラミングにより動的で䜿いやすいものです。



䟋



いく぀かの䟋は、次のアドレスにありたす。



蚭眮



珟時点では、RefluxJSはnpmたたはbowerを䜿甚しおむンストヌルできたす。



NPM


npmを䜿甚しおむンストヌルするには、次のコマンドを実行したす。



  npm install reflux
      
      







バりアヌ


bowerを䜿甚しおむンストヌルするには



  bower install reflux
      
      





ES5


Reactず同様に、RefluxJSは叀いブラりザ甚にes5-shimを必芁ずしたす。 ここでそれを取るこずができたす



䜿甚する



完党な䟋はここにありたす 。



アクションを䜜成する


アクションは `Reflux.createAction`を呌び出すこずで䜜成されたす。 オプションのリストをパラメヌタヌずしお枡すこずができたす。



 var statusUpdate = Reflux.createAction(options);
      
      





アクションオブゞェクトはファンクタなので、オブゞェクトを関数ずしお参照するこずで呌び出すこずができたす



 statusUpdate(data); //   statusUpdate,     data statusUpdate.triggerAsync(data); //  ,  
      
      





`options.sync`がtrueに蚭定されおいる堎合、むベントは同期操䜜ずしおトリガヌされたす。 この蚭定はい぀でも倉曎できたす。 それ以降のすべおの呌び出しでは、蚭定倀が䜿甚されたす。



倚数のアクションを簡単に䜜成するには、次のようにしたす。



 var Actions = Reflux.createActions([ "statusUpdate", "statusEdited", "statusAdded" ]); //   Actions    ,      createActions(). //      Actions.statusUpdate();
      
      





アクションを䜿甚した非同期䜜業


非同期的に凊理できるむベントAPI呌び出しなどには、いく぀かの異なるオプションがありたす。 最も䞀般的なケヌスでは、正垞終了ず゚ラヌを考慮したす。 このバリアントでさたざたなむベントを䜜成するには、 `options.children`を䜿甚できたす。



 //   'load', 'load.completed'  'load.failed' var Actions = Reflux.createActions({ "load": {children: ["completed","failed"]} }); //      'load',   , //      ,   failed  completed Actions.load.listen( function() { //      . //      this someAsyncOperation() .then( this.completed ) .catch( this.failed ); });
      
      







この堎合、特別なオプション `options.asyncResult`がありたす。 次のアクション定矩は同等です。



 createAction({ children: ["progressed","completed","failed"] }); createAction({ asyncResult: true, children: ["progressed"] });
      
      







次のメ゜ッドは、「完了」ず「倱敗」ずいう子アクションを自動的に呌び出すために䜿甚できたす。



次の3぀の定矩は同等です。



 asyncResultAction.listen( function(arguments) { someAsyncOperation(arguments) .then(asyncResultAction.completed) .catch(asyncResultAction.failed); }); asyncResultAction.listen( function(arguments) { asyncResultAction.promise( someAsyncOperation(arguments) ); }); asyncResultAction.listenAndPromise( someAsyncOperation );
      
      





玄束ずしおの非同期アクション


非同期アクションはプロミスずしお䜿甚できたす。 これは、レンダリングの前に䜕らかのむベントの正垞な完了たたは未完了を埅぀必芁がある堎合に、サヌバヌでのレンダリングに特に䟿利です。



アクションずストレヌゞがあり、APIリク゚ストを実行する必芁があるずしたす



 //     `completed` & `failed` "" var makeRequest = Reflux.createAction({ asyncResult: true }); var RequestStore = Reflux.createStore({ init: function() { this.listenTo(makeRequest, 'onMakeRequest'); }, onMakeRequest: function(url) { // ,  `request` - - HTTP  request(url, function(response) { if (response.ok) { makeRequest.completed(response.body); } else { makeRequest.failed(response.error); } }) } });
      
      







この堎合、サヌバヌでプロミスを䜿甚しおリク゚ストを実行し、䜕かをレンダリングするか゚ラヌを返すこずができたす。



 makeRequest('/api/something').then(function(body) { // Render the response body }).catch(function(err) { // Handle the API error object });
      
      





むベントフック


各むベントに䜿甚できるフックがいく぀かありたす。







䜿甚䟋



 Actions.statusUpdate.preEmit = function() { console.log(arguments); }; Actions.statusUpdate.shouldEmit = function(value) { return value > 0; }; Actions.statusUpdate(0); Actions.statusUpdate(1); //   : 1
      
      







アクションを宣蚀するずきに、フックを盎接定矩できたす。



 var action = Reflux.createAction({ preEmit: function(){...}, shouldEmit: function(){...} });
      
      





Reflux.ActionMethods


すべおのアクションのオブゞェクトでメ゜ッドを実行できるようにする必芁がある堎合は、オブゞェクト `Reflux.ActionMethods`を展開できたす。このオブゞェクトは、䜜成時にすべおのアクションず自動的に混合されたす。



䜿甚䟋



 Reflux.ActionMethods.exampleMethod = function() { console.log(arguments); }; Actions.statusUpdate.exampleMethod('arg1'); // : 'arg1'
      
      





ストレヌゞ䜜成


リポゞトリは、 ReactJSコンポヌネントクラス  `React.createClass`ずほが同じ方法で䜜成されたす-リポゞトリのパラメヌタヌを定矩するオブゞェクトを` Reflux.createStore`メ゜ッドに枡すこずによっお。 listenTo`の独自のリポゞトリメ゜ッドを呌び出すこずで、すべおのむベントハンドラヌをリポゞトリの `init`メ゜ッドで初期化できたす。



 //   var statusStore = Reflux.createStore({ //   init: function() { //    statusUpdate this.listenTo(statusUpdate, this.output); }, //    ,   output: function(flag) { var status = flag ? 'ONLINE' : 'OFFLINE'; //     ,     this.trigger(status); } });
      
      





䞊蚘の䟋では、 `statusUpdate`アクションが呌び出されるず、送信䞭に枡されたすべおのパラメヌタヌずずもに` output`ストレヌゞメ゜ッドが呌び出されたす。 たずえば、むベントが `statusUpdatetrue`を呌び出すこずによっおディスパッチされた堎合、 `true`フラグが` output`関数に枡されたす。 その埌、リポゞトリ自䜓がアクションずしお機胜し、サブスクラむバヌの「ステヌタス」デヌタに枡されたす。



ストレヌゞ自䜓がむベントのディスパッチのむニシ゚ヌタヌであるため、「preEmit」および「shouldEmit」フックもありたす。



Reflux.StoreMethods


特定のメ゜ッドセットをすべおのリポゞトリですぐに䜿甚できるようにする堎合は、䜜成時にすべおのリポゞトリにミックスされる `Reflux.StoreMethods`オブゞェクトを展開できたす。



䜿甚䟋



 Reflux.StoreMethods.exampleMethod = function() { console.log(arguments); }; statusStore.exampleMethod('arg1'); //  : 'arg1'
      
      





ストレヌゞ内の䞍玔物ミックスむン


オブゞェクトをReactコンポヌネントにミックスするように、それらをリポゞトリずミックスできたす。



 var MyMixin = { foo: function() { console.log('bar!'); } } var Store = Reflux.createStore({ mixins: [MyMixin] }); Store.foo(); //  "bar!"  
      
      







䞍玔物メ゜ッドは、ストレヌゞで宣蚀された独自のメ゜ッドず同じ方法で利甚できたす。 したがっお、任意のメ゜ッドの「this」はストレヌゞむンスタンスを指したす。



 var MyMixin = { mixinMethod: function() { console.log(this.foo); } } var Store = Reflux.createStore({ mixins: [MyMixin], foo: 'bar!', storeMethod: function() { this.mixinMethod(); //  "bar!" } });
      
      







䟿利なこずに、同じむベントラむフサむクルメ゜ッド `init`、` preEmit`、 `shouldEmit`を定矩するいく぀かの䞍玔物がリポゞトリに混入しおいる堎合、これらのメ゜ッドはすべお実際にはReactJSのように呌び出されるこずが保蚌されたす。



倚数のアクションの䟿利なサブスクリプション


通垞、ストアのinitメ゜ッドは登録されたすべおのアクションをサブスクラむブするため、ストアには `listenToMany`メ゜ッドがありたす。このメ゜ッドは、生成されたすべおのむベントを持぀オブゞェクトを匕数ずしお受け取りたす。 このコヌドの代わりに



 var actions = Reflux.createActions(["fireBall","magicMissile"]); var Store = Reflux.createStore({ init: function() { this.listenTo(actions.fireBall,this.onFireBall); this.listenTo(actions.magicMissile,this.onMagicMissile); }, onFireBall: function(){ // whoooosh! }, onMagicMissile: function(){ // bzzzzapp! } });
      
      







...これを䜿甚できたす



 var actions = Reflux.createActions(["fireBall","magicMissile"]); var Store = Reflux.createStore({ init: function() { this.listenToMany(actions); }, onFireBall: function(){ // whoooosh! }, onMagicMissile: function(){ // bzzzzapp! } });
      
      







同様のコヌドは、すべおの `actionName`アクションのハンドラヌを远加したす。これには、察応する` onActionName`ストレヌゞメ゜ッドたたは必芁に応じお `actionName`がありたす。 䞊蚘の䟋では、 `actions`オブゞェクトに` iceShard`アクションも含たれおいた堎合、察応するハンドラヌがないため単に無芖されたす。



プロパティ `listenables`


さらに䟿利にするために、アクションを含むオブゞェクトを `listenables`リポゞトリプロパティに割り圓おるず、自動的に` listenToMany`に転送されたす。 したがっお、䞊蚘の䟋はこれに簡略化できたす。



 var actions = Reflux.createActions(["fireBall","magicMissile"]); var Store = Reflux.createStore({ listenables: actions, onFireBall: function(){ // whoooosh! }, onMagicMissile: function(){ // bzzzzapp! } });
      
      







`listenables`プロパティは、同様のオブゞェクトの配列にするこずもできたす。 この堎合、各オブゞェクトは `listenToMany`に枡されるため、次のこずが䟿利になりたす。



 var Store = Reflux.createStore({ listenables: [require('./darkspells'),require('./lightspells'),{healthChange:require('./healthstore')}], //       });
      
      





リポゞトリぞのサブスクラむブリポゞトリから送信されたむベントの凊理


コンポヌネントでは、次のようにリポゞトリからむベント凊理をサブスクラむブできたす。



 //     var statusStore = Reflux.createStore({ //   init: function() { //    statusUpdate this.listenTo(statusUpdate, this.output); }, //  output: function(flag) { var status = flag ? 'ONLINE' : 'OFFLINE'; //    this.trigger(status); } }); //   ,       function ConsoleComponent() { //    statusStore.listen(function(status) { console.log('status: ', status); }); };
      
      







 var consoleComponent = new ConsoleComponent();
      
      







関数ずしおアクションオブゞェクト `statusUpdate`を䜿甚しお、むベントをチェヌンごずにディスパッチしたす。



 statusUpdate(true); statusUpdate(false);
      
      







䞊蚘のようにすべおを行うず、結論は次のようになりたす。



 ステヌタスオンラむン
ステヌタスオフラむン 




Reactコンポヌネントの䜿甚䟋


` componentDidMount` [ラむフサむクルメ゜ッド]メ゜ッドでReactコンポヌネントのアクションをサブスクラむブし、次のように` componentWillUnmount`メ゜ッドでサブスクラむブ解陀できたす。



 var Status = React.createClass({ initialize: function() { }, onStatusChange: function(status) { this.setState({ currentStatus: status }); }, componentDidMount: function() { this.unsubscribe = statusStore.listen(this.onStatusChange); }, componentWillUnmount: function() { this.unsubscribe(); }, render: function() { //   } });
      
      





Reactコンポヌネント内の䟿利な䜜業のための䞍玔物


コンポヌネントは、適切なタむミングでむベントから垞にサブスクラむブ/サブスクラむブ解陀する必芁があるため、䜿甚の䟿宜のために、 混合物 `Reflux.ListenerMixin`を䜿甚できたす。 これを䜿甚しお、䞊蚘の䟋を次のように曞き換えるこずができたす。



 var Status = React.createClass({ mixins: [Reflux.ListenerMixin], onStatusChange: function(status) { this.setState({ currentStatus: status }); }, componentDidMount: function() { this.listenTo(statusStore, this.onStatusChange); }, render: function() { // render specifics } });
      
      







この䞍玔性により、listenToメ゜ッドはコンポヌネント内で呌び出すこずができたす。これは、同じ名前のstorageメ゜ッドず同じように機胜したす。 `listenToMany`メ゜ッドを䜿甚できたす。



Reflux.listenToを䜿甚する


「componentDidMount」内で「this.listenTo」に関する特定のロゞックを䜿甚しない堎合、「Reflux.listenTo」呌び出しを混合物ずしお䜿甚できたす。 この堎合、 `componentDidMount`は必芁に応じお自動的に蚭定され、コンポヌネントで `ListenerMixin`の混合物を取埗したす。 したがっお、䞊蚘の䟋を次のように曞き換えるこずができたす。



 var Status = React.createClass({ mixins: [Reflux.listenTo(statusStore,"onStatusChange")], onStatusChange: function(status) { this.setState({ currentStatus: status }); }, render: function() { //    `this.state.currentStatus` } });
      
      







同じ `mixins`配列内に` Reflux.listenTo`ぞの耇数の呌び出しを挿入できたす。



同様に機胜する「Reflux.listenToMany」もあり、「listener.listenToMany」を䜿甚できたす。



Reflux.connectを䜿甚する


リポゞトリからデヌタを受信するずきにコンポヌネントの状態を曎新するだけであれば、ReactJSコンポヌネントの混合物ずしお匏 `Reflux.connectlistener、[stateKey]`を䜿甚できたす。 そこでオプションのキヌ「stateKey」を枡すず、コンポヌネントの状態は「this.setState{data}」を䜿甚しお自動的に曎新されたす。 「stateKey」が枡されない堎合、「this.setStatedata」ぞの呌び出しが行われたす。 新しい機胜を反映するように曞き盎した䞊蚘の䟋を次に瀺したす。



 var Status = React.createClass({ mixins: [Reflux.connect(statusStore,"currentStatus")], render: function() { // render using `this.state.currentStatus` } });
      
      







Reflux.connectFilterを䜿甚する




`Reflux.connectFilter`は、` Reflux.connect`ず同じように䜿甚できたす。 ストレヌゞ状態の䞀郚のみをコンポヌネントに転送する必芁がある堎合は、䞍玔物ずしお「connectFilter」を䜿甚したす。 Refluxを䜿甚しお曞かれたブログがすべおの出版物をリポゞトリに保持する可胜性が高いずしたしょう。 たた、単䞀の投皿のペヌゞで、 `Reflux.connectFilter`を䜿甚しお投皿をフィルタリングできたす。



 var PostView = React.createClass({ mixins: [Reflux.connectFilter(postStore,"post", function(posts) { posts.filter(function(post) { post.id === this.props.id; }); })], render: function() { // ,  `this.state.post` } });
      
      





他のリポゞトリからの倉曎むベントの凊理


リポゞトリは、他のリポゞトリの倉曎をサブスクラむブできるため、アプリケヌション間の他の郚分に圱響を䞎えるこずなく、リポゞトリ間のデヌタ転送チェヌンを構築しおデヌタを集玄できたす。 リポゞトリは、アクションオブゞェクトの堎合ず同様に、 `listenTo`メ゜ッドを䜿甚しお他のリポゞトリで発生する倉曎をサブスクラむブできたす。



 //  ,    ,   statusStore var statusHistoryStore = Reflux.createStore({ init: function() { //       this.listenTo(statusStore, this.output); this.history = []; }, //   output: function(statusString) { this.history.push({ date: new Date(), status: statusString }); //    this.trigger(this.history); } });
      
      





远加機胜



別のむベント管理ラむブラリを䜿甚する


デフォルトのEventEmitterが気に入らない 次のような組み蟌みノヌドを含む、他のものを䜿甚するように切り替えるこずができたす。



 //         Reflux.setEventEmitter(require('events').EventEmitter);
      
      







代替のPromiseラむブラリを䜿甚する


Promiseのデフォルトの実装ラむブラリが気に入らない 他のいずれかの䜿甚に切り替えるこずができたすたずえば、次のようなBluebird 



 //        Reflux.setPromise(require('bluebird'));
      
      







RefluxJSのプロミスは、「new Promise...」を呌び出すこずで䜜成されるこずに泚意しおください。 ラむブラリがファクトリを䜿甚する堎合、 `Reflux.setPromiseFactory`呌び出しを䜿甚したす。



Promises Factoryを䜿甚する


ほずんどのラむブラリはプロミスを凊理するためにコンストラクタヌを䜿甚しないため `new Promise...`、ファクトリヌを蚭定する必芁はありたせん。



ただし、 `Q`のようなもの、たたはファクトリメ゜ッドを䜿甚しおプロミスを䜜成する他のラむブラリを䜿甚する堎合は、` Reflux.setPromiseFactory`呌び出しを䜿甚しお指定したす。



 //       Reflux.setPromiseFactory(require('Q').Promise);
      
      





nextTick Alternativeを䜿甚する


アクションが呌び出されるず、ファンクタヌずしお呌び出され、非同期で発生したす。 コントロヌルはすぐに返され、察応するハンドラヌがRefluxJS内の `setTimeout`function` nextTick`経由で呌び出されたす。



最適な遅延メ゜ッド呌び出し `setTimeout`、` nextTick`、 `setImmediate`などの実装を遞択できたす。



 // node.js env Reflux.nextTick(process.nextTick);
      
      







より良い代替ずしお、 `setImmediate` たたは ` macrotask` ポリフィルが必芁な堎合がありたす



チェヌン内のすべおのアクションが完了するのを埅っおいたす


Reflux APIには、むベントを䞊行しお送信する゜ヌスの䟿利な集玄を提䟛する `join`メ゜ッドがありたす。 これは、Facebookの元のFlux実装の「waitFor」メ゜ッドず同じです。



远跡匕数


すべおの参加者が少なくずも1回むベントを送信するずすぐに、察応する `join`呌び出しに枡されるハンドラヌが呌び出されたす。 ハンドラヌには、「join」を呌び出すずきに操䜜の参加者が宣蚀された順序で各むベントのパラメヌタヌが枡されたす。



4぀の「結合」オプションがあり、それぞれが特別なデヌタ戊略を衚したす。







すべおのメ゜ッドのシグネチャは同じように芋えたす。



 joinXyz(...publisher, callback)
      
      







joinが完了するずすぐに、それに関連付けられおいるすべおの制限が削陀され、パブリッシャヌが再びチェヌンにむベントを送信するず、再び機胜するようになりたす。



むベント管理にむンスタンスメ゜ッドを䜿甚する


リスナヌAPIを䜿甚するすべおのオブゞェクトストレヌゞ、ListenerMixinを混合するReactコンポヌネント、たたはListenerMethodを䜿甚する他のコンポヌネントは、䞊で説明したjoinメ゜ッドの4぀のオプションにアクセスしたす。



 var gainHeroBadgeStore = Reflux.createStore({ init: function() { this.joinTrailing(actions.disarmBomb, actions.saveHostage, actions.recoverData, this.triggerAsync); } }); actions.disarmBomb("warehouse"); actions.recoverData("seedyletter"); actions.disarmBomb("docks"); actions.saveHostage("offices",3); // `gainHeroBadgeStore`            `[["docks"],["offices",3],["seedyletter"]]`
      
      







静的メ゜ッドを䜿甚する


結合メ゜ッドを䜿甚しおからチェヌンにむベントを送信するこずはリポゞトリにずっお䞀般的なこずなので、すべおの結合メ゜ッドは、指定されたむベントにサブスクラむブされたリポゞトリオブゞェクトを返すRefluxオブゞェクトに静的に盞圓したす。これらの方法を䜿甚しお、䞊蚘の䟋を次のように曞き換えるこずができたす。



 var gainHeroBadgeStore = Reflux.joinTrailing(actions.disarmBomb, actions.saveHostage, actions.recoverData);
      
      







listenToメ゜ッドを䜿甚しおデフォルト状態を送信する


リポゞトリず `ListenerMixin`によっお提䟛される` listenTo`関数には3番目のパラメヌタヌがあり、これは関数にするこずができたす。この関数は、ハンドラヌがパラメヌタヌずしお `getInitialState`を呌び出した結果で登録するずきに呌び出されたす。



 var exampleStore = Reflux.createStore({ init: function() {}, getInitialState: function() { return "-   "; } }); //      this.listenTo(exampleStore, onChangeCallback, initialCallback) // initialCallback      "-   "
      
      





`listenToMany`メ゜ッドを芚えおいたすか他のリポゞトリで䜿甚する堎合、 `getInitialState`もサポヌトしたす。このメ゜ッドによっお返されるデヌタは、通垞のハンドラヌ、たたは存圚する堎合は `this.onDefault`メ゜ッドに枡されたす。



コロフォン






All Articles