apeescape2.com
  • メイン
  • ヒントとツール
  • 分散チーム
  • アジャイル
  • プロジェクト管理
データサイエンスとデータベース

フラックスとバックボーンを使用したReactアプリの単純なデータフロー:例を含むチュートリアル

React.js 素晴らしい図書館です。 Pythonをスライスして以来、それが最良のように思えることもあります。ただし、Reactはフロントエンドアプリケーションスタックの一部にすぎません。データと状態の管理に関しては、提供できるものはそれほど多くありません。

ReactのメーカーであるFacebookは いくつかのガイダンスを提供しました の形でそこに フラックス 。 Fluxは、Reactビュー、アクションディスパッチャー、およびストアを使用して一方向のデータフローを中心に構築された「アプリケーションアーキテクチャ」(フレームワークではありません)です。 Fluxパターンは、イベント制御の重要な原則を具体化することによっていくつかの主要な問題を解決します。これにより、Reactアプリケーションの推論、開発、および保守がはるかに簡単になります。

ここでは、制御フローの基本的なFluxの例を紹介し、ストアに欠けているものと、バックボーンモデルとコレクションを使用して「Flux準拠」の方法でギャップを埋める方法について説明します。



(注:便宜上、簡潔にするために、例ではCoffeeScriptを使用しています。CoffeeScript以外の開発者は、従うことができ、例を擬似コードとして扱うことができます。)

Facebookのフラックスの紹介

背骨 は、ビュー、モデル、コレクション、およびルートを含む、優れた、十分に吟味された小さなライブラリです。それは デファクト 構造化フロントエンドアプリケーションの標準ライブラリであり、2013年にReactアプリが導入されて以来、Reactアプリとペアになっています。これまでのFacebook.com以外のReactのほとんどの例には、Backboneがタンデムで使用されているという言及が含まれています。

残念ながら、Reactのビュー以外のアプリケーションフロー全体を処理するためにバックボーンだけに頼ると、不幸な問題が発生します。私が最初にReact-Backboneアプリケーションコードの作業を始めたとき、私が持っていた「複雑なイベントチェーン」 について読む ヒドラのような頭を育てるのにそれほど時間はかかりませんでした。 UIからモデルにイベントを送信し、次にあるモデルから別のモデルにイベントを送信してから再度送信すると、誰が誰を、どの順序で、なぜ変更したかを追跡するのが困難になります。

このFluxチュートリアルでは、Fluxパターンがこれらの問題を驚くほど簡単かつシンプルに処理する方法を示します。

概要

Fluxのスローガンは「一方向のデータフロー」です。これはからの便利な図です フラックスドキュメント そのフローがどのように見えるかを示します。

Facebook Fluxは、ReactおよびBackboneと組み合わせると少し変化する「一方向データフロー」モデルを使用します。

重要なのは、React --> Dispatcher --> Stores --> Reactからデータが流れるということです。

各主要コンポーネントとは何か、およびそれらがどのように接続されているかを見てみましょう。

ドキュメントには、この重要な警告も記載されています。

Fluxはフレームワークというよりもパターンであり、強い依存関係はありません。ただし、ストアのベースとしてEventEmitterを使用し、ビューのReactを使用することがよくあります。他の場所ではすぐに利用できないフラックスの1つは、ディスパッチャーです。このモジュールは、Fluxツールボックスを完成させるためにここから入手できます。

したがって、Fluxには3つのコンポーネントがあります。

  1. ビュー(React = require('react'))
  2. コーディネーター(Dispatcher = require('flux').Dispatcher)
  3. 店舗(EventEmitter = require('events').EventEmitter)
    • (または、すぐにわかるように、Backbone = require('backbone'))

ビュー

Reactについては、Angularよりも非常に好むと言う以外に多くのことが書かれているため、ここでは説明しません。私はほとんど感じません 混乱している Angularとは異なり、Reactコードを作成する場合、もちろん意見は異なります。

ディスパッチャ

Flux Dispatcherは、ストアを変更するすべてのイベントが処理される単一の場所です。それを使用するには、各ストアがありますregisterすべてのイベントを処理するための単一のコールバック。そうすれば、ストアを変更するときはいつでもdispatchイベント。

c ++の高度なチュートリアル

Reactのように、Dispatcherは、うまく実装された良いアイデアだと思います。例として、ユーザーがToDoリストに項目を追加できるアプリには次のものがあります。

# in TodoDispatcher.coffee Dispatcher = require('flux').Dispatcher TodoDispatcher = new Dispatcher() # That's all it takes!. module.exports = TodoDispatcher # in TodoStore.coffee TodoDispatcher = require('./TodoDispatcher') TodoStore = {items: []} TodoStore.dispatchCallback = (payload) -> switch payload.actionType when 'add-item' TodoStore.items.push payload.item when 'delete-last-item' TodoStore.items.pop() TodoStore.dispatchToken = TodoDispatcher.registerCallback(TodoStore.dispatchCallback) module.exports = TodoStore # in ItemAddComponent.coffee TodoDispatcher = require('./TodoDispatcher') ItemAddComponent = React.createClass handleAddItem: -> # note: you're NOT just pushing directly to the store! # (the restriction of moving through the dispatcher # makes everything much more modular and maintainable) TodoDispatcher.dispatch actionType: 'add-item' item: 'hello world' render: -> React.DOM.button { onClick: @handleAddItem }, 'Add an Item!'

これにより、次の2つの質問に簡単に答えることができます。

  1. Q:MyStoreを変更するすべてのイベントは何ですか?
    • A:switchでケースを確認してくださいMyStore.dispatchCallbackのステートメント。
  2. Q:そのイベントの考えられるすべての原因は何ですか?
    • A:そのactionTypeを検索するだけです。

これは、たとえばMyModel.setを探すよりもはるかに簡単です。 そして MyModel.save そして MyCollection.addなど、これらの基本的な質問への回答を追跡することは非常に速く非常に困難になります。

Dispatcherでは、waitForを使用して、コールバックを単純な同期方式で順次実行することもできます。例えば:

# in MessageStore.coffee MyDispatcher = require('./MyDispatcher') TodoStore = require('./TodoStore') MessageStore = {items: []} MessageStore.dispatchCallback = (payload) -> switch payload.actionType when 'add-item' # synchronous event flow! MyDispatcher.waitFor [TodoStore.dispatchToken] MessageStore.items.push 'You added an item! It was: ' + payload.item module.exports = MessageStore

実際には、waitForを使用しなくても、ディスパッチャーを使用してストアを変更すると、コードがどれほどクリーンになるかを見てショックを受けました。

cまたはc ++を学ぶ

店舗

したがって、データフロー に ディスパッチャを介して保存します。とった。しかし、データはストアからビューにどのように流れますか(つまり、React)?で述べたように フラックスドキュメント :

[]ビューは、依存するストアによってブロードキャストされるイベントをリッスンします。

いいでしょうストアにコールバックを登録したのと同じように、ビュー(Reactコンポーネント)にコールバックを登録します。 Reactに再-renderを指示しますpropsを介して渡されたストアで変更が発生したときはいつでも。

例えば:

# in TodoListComponent.coffee React = require('react') TodoListComponent = React.createClass componentDidMount: -> @props.TodoStore.addEventListener 'change', => @forceUpdate() , @ componentWillUnmount: -> # remove the callback render: -> # show the items in a list. React.DOM.ul {}, @props.TodoStore.items.map (item) -> React.DOM.li {}, item

驚くばかり!

では、どのようにそれを放出するのでしょうか'change'イベント?さて、FluxはEventEmitterの使用をお勧めします。公式の例から:

var MessageStore = merge(EventEmitter.prototype, { emitChange: function() { this.emit(CHANGE_EVENT); }, /** * @param {function} callback */ addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, get: function(id) { return _messages[id]; }, getAll: function() { return _messages; }, // etc...

キモい!シンプルなストアが必要になるたびに、自分ですべてを書く必要がありますか?表示したい情報があるたびに使用することになっているのはどれですか?より良い方法が必要です!

行方不明の作品

バックボーンのモデルとコレクションには、FluxのEventEmitterベースのストアが行っているように見えるすべてのものがすでに含まれています。

生のEventEmitterを使用するように指示することにより、Fluxは、ストアを作成するたびに、Backboneのモデルとコレクションの50〜75%を再作成することをお勧めします。店舗にEventEmitterを使用することは、Express.jsなどの十分に構築されたマイクロフレームワークがすでに存在し、すべての基本と定型文を処理する場合に、サーバーに裸のNode.jsを使用することに似ています。

Express.jsがNode.js上に構築されているように、BackboneのモデルとコレクションはEventEmitter上に構築されています。そして、それはあなたがほとんどいつも必要とするすべてのものを持っています:バックボーンはchangeを放出しますイベントがあり、クエリメソッド、ゲッター、セッターなどすべてがあります。さらに、バックボーンの ジェレミー・アシュケナス と彼の軍隊 230人の寄稿者 私ができると思われるよりも、これらすべてのことではるかに優れた仕事をしました。

このバックボーンチュートリアルの例として、MessageStoreの例を上からに変換しました バックボーンバージョン 。

客観的にコードが少なく(作業を複製する必要がない)、主観的により明確で簡潔です(たとえば、this.add(message)の代わりに_messages[message.id] = message)。

それでは、バックボーンをストアに使用しましょう。

FluxBoneパターン:バックボーンによるフラックスストア

このチュートリアルは、私が誇らしげに吹き替えたアプローチの基礎です FluxBone 、Backbone forStoresを使用したFluxアーキテクチャ。 FluxBoneアーキテクチャの基本的なパターンは次のとおりです。

  1. ストアは、ディスパッチャーにコールバックを登録した、インスタンス化されたバックボーンモデルまたはコレクションです。通常、これはそれらがシングルトンであることを意味します。
  2. コンポーネントを表示する 決して ストアを直接変更します(たとえば、.set()はありません)。代わりに、コンポーネントはアクションをディスパッチャーにディスパッチします。
  3. コンポーネントのクエリストアを表示し、それらのイベントにバインドして更新をトリガーします。

このバックボーンチュートリアルは、Reactアプリケーションでバックボーンとフラックスがどのように連携するかを確認するように設計されています。

バックボーンとフラックスの例を使用して、その各部分を順番に見ていきましょう。

1.ストアは、ディスパッチャーにコールバックを登録した、インスタンス化されたバックボーンモデルまたはコレクションです。

# in TodoDispatcher.coffee Dispatcher = require('flux').Dispatcher TodoDispatcher = new Dispatcher() # That's all it takes! module.exports = TodoDispatcher # in stores/TodoStore.coffee Backbone = require('backbone') TodoDispatcher = require('../dispatcher') TodoItem = Backbone.Model.extend({}) TodoCollection = Backbone.Collection.extend model: TodoItem url: '/todo' # we register a callback with the Dispatcher on init. initialize: -> @dispatchToken = TodoDispatcher.register(@dispatchCallback) dispatchCallback: (payload) => switch payload.actionType # remove the Model instance from the Store. when 'todo-delete' @remove payload.todo when 'todo-add' @add payload.todo when 'todo-update' # do stuff... @add payload.todo, merge: true # ... etc # the Store is an instantiated Collection; a singleton. TodoStore = new TodoCollection() module.exports = TodoStore

2.コンポーネント 決して ストアを直接変更します(たとえば、.set()はありません)。代わりに、コンポーネントはアクションをディスパッチャーにディスパッチします。

# components/TodoComponent.coffee React = require('react') TodoListComponent = React.createClass handleTodoDelete: -> # instead of removing the todo from the TodoStore directly, # we use the Dispatcher TodoDispatcher.dispatch actionType: 'todo-delete' todo: @props.todoItem # ... (see below) ... module.exports = TodoListComponent

3.コンポーネントはストアにクエリを実行し、それらのイベントにバインドして更新をトリガーします。

# components/TodoComponent.coffee React = require('react') TodoListComponent = React.createClass handleTodoDelete: -> # instead of removing the todo from the TodoStore directly, # we use the dispatcher. #flux TodoDispatcher.dispatch actionType: 'todo-delete' todo: @props.todoItem # ... componentDidMount: -> # the Component binds to the Store's events @props.TodoStore.on 'add remove reset', => @forceUpdate() , @ componentWillUnmount: -> # turn off all events and callbacks that have this context @props.TodoStore.off null, null, this render: -> React.DOM.ul {}, @props.TodoStore.items.map (todoItem) -> # TODO: TodoItemComponent, which would bind to # `this.props.todoItem.on('change')` TodoItemComponent { todoItem: todoItem } module.exports = TodoListComponent

私はこのフラックスとバックボーンのアプローチを自分のプロジェクトに適用しました。このパターンを使用するようにReactアプリケーションを再構築すると、ほとんどすべての醜いビットが消えました。それは少し奇跡的でした。より良い方法を探して歯を食いしばったコードの断片が、賢明な流れに置き換えられました。そして、Backboneがこのパターンに統合されているように見える滑らかさは注目に値します。単一のアプリケーションにそれらを合わせるために、Backbone、Flux、またはReactと戦っているような気がしません。

Mixinの例

this.on(...)を書くおよびthis.off(...) FluxBoneストアをコンポーネントに追加するたびに、コードが少し古くなる可能性があります。

これは、React Mixinの例です。これは、非常に単純ですが、確実にすばやく反復するのがさらに簡単になります。

# in FluxBoneMixin.coffee module.exports = (propName) -> componentDidMount: -> @props[propName].on 'all', => @forceUpdate() , @ componentWillUnmount: -> @props[propName].off 'all', => @forceUpdate() , @ # in HelloComponent.coffee React = require('react') UserStore = require('./stores/UserStore') TodoStore = require('./stores/TodoStore') FluxBoneMixin = require('./FluxBoneMixin') MyComponent = React.createClass mixins: [ FluxBoneMixin('UserStore'), FluxBoneMixin('TodoStore'), ] render: -> React.DOM.div {}, 'Hello, #{ @props.UserStore.get('name') }, you have #{ @props.TodoStore.length } things to do.' React.renderComponent( MyComponent { UserStore: UserStore TodoStore: TodoStore } , document.body.querySelector('.main') )

WebAPIとの同期

元のFluxダイアグラムでは、ActionCreatorを介してのみWeb APIと対話します。これは、アクションをDispatcherに送信する前にサーバーからの応答を必要とします。それは私には決して正しくありませんでした。サーバーの前に、ストアが変更について最初に知っているべきではありませんか?

図のその部分を裏返すことにしました。ストアは、バックボーンのsync()を介してRESTfulCRUDAPIと直接対話します。これは、少なくとも実際のRESTful CRUD APIを使用している場合は、非常に便利です。

データの整合性は問題なく維持されます。あなたが.set()するとき新しいプロパティ、changeイベントはReactの再レンダリングをトリガーし、新しいデータを楽観的に表示します。 .save()をしようとするとサーバーに送信しますrequestイベントは、読み込みアイコンを表示することを通知します。物事が進むと、syncイベントは、読み込みアイコン、またはerrorを削除することを通知しますイベントはあなたに物事を赤くすることを知らせます。あなたはインスピレーションを見ることができます ここに 。

防御の第1層の検証(および対応するinvalidイベント)と.fetch()もありますサーバーから新しい情報を取得する方法。

ウェブサイトからメタマスクに接続する方法

標準的でないタスクの場合、ActionCreatorsを介した対話の方が理にかなっている場合があります。 Facebookは「単なるCRUD」をあまり行っていないのではないかと思います。その場合、Facebookがストアを最優先しないのは当然のことです。

結論

Facebookのエンジニアリングチームは、 フロントエンドWebを前方にプッシュ と React 、およびFluxの導入により、テクノロジーだけでなくエンジニアリングの観点からも、真に拡張可能なより広範なアーキテクチャを垣間見ることができます。バックボーンを巧妙かつ注意深く使用すると(このチュートリアルの例による)、Fluxのギャップを埋めることができ、個人のインディーショップから大企業まで、誰でも印象的なアプリケーションを作成して維持することが驚くほど簡単になります。

関連: ReactコンポーネントがUIテストを容易にする方法

成功する市場開拓戦略を作成する方法

財務プロセス

成功する市場開拓戦略を作成する方法
言葉と行動–マイクロコピーのガイド

言葉と行動–マイクロコピーのガイド

Uxデザイン

人気の投稿
UXとWebアクセシビリティの重要性
UXとWebアクセシビリティの重要性
成功の予測—現金管理のガイド
成功の予測—現金管理のガイド
アプリを収益性の高いものにする、パート2 –モバイルファネルの活用
アプリを収益性の高いものにする、パート2 –モバイルファネルの活用
優れたUXデザインが必要ですか?あなたの自我を落としてください。
優れたUXデザインが必要ですか?あなたの自我を落としてください。
ユーザーフローの強化–UX分析のガイド
ユーザーフローの強化–UX分析のガイド
 
データの視覚化–ベストプラクティスと基盤
データの視覚化–ベストプラクティスと基盤
IoTバリューチェーンを登る
IoTバリューチェーンを登る
良いか悪いかを変える? UXイノベーションのガイド
良いか悪いかを変える? UXイノベーションのガイド
生体認証セキュリティ–パスワードなしの認証または流行の鍵?
生体認証セキュリティ–パスワードなしの認証または流行の鍵?
どこでもソフトウェア開発:私の分散型リモートワークプレイス
どこでもソフトウェア開発:私の分散型リモートワークプレイス
人気の投稿
  • オプション価格の計算方法
  • Googleスプレッドシートでマクロを使用する
  • cssメディアクエリ標準ブレークポイント
  • Pythonでクラスを宣言する
  • アマゾンウェブサービス認定ソリューションアーキテクト
  • 需要の価格弾力性の概念
  • javascripttypeerrorは関数ではありません
カテゴリー
収益性と効率性 革新 プロジェクト管理 人とチーム Kpiと分析 分散チーム その他 投資家と資金調達 ライフスタイル アジャイルタレント

© 2021 | 全著作権所有

apeescape2.com