回答:
私は、アクションの作成者に非同期の書き込み操作を、ストアに非同期の読み取り操作を置くことを強く支持しています。目標は、ストア状態変更コードを完全に同期したアクションハンドラーに保持することです。これにより、推論が簡単になり、単体テストも簡単になります。同じエンドポイントへの複数の同時要求(たとえば、二重読み取り)を防ぐために、実際の要求処理を、複数の要求を防ぐためのpromiseを使用する別のモジュールに移動します。例えば:
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
ストアでの読み取りには非同期関数が含まれますが、ストアは非同期ハンドラーで自分自身を更新せず、代わりにアクションを起動し、応答が到着したときにのみアクションを起動するという重要な警告があります。このアクションのハンドラーは、実際の状態変更を行います。
たとえば、コンポーネントは次のことを行う場合があります。
getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}
ストアには、おそらく次のようなメソッドが実装されています。
class Store {
getSomeData(id) {
if (!this.cache[id]) {
MyResurceDAO.get(id).then(this.updateFromServer);
this.cache[id] = LOADING_TOKEN;
// LOADING_TOKEN is a unique value of some kind
// that the component can use to know that the
// value is not yet available.
}
return this.cache[id];
}
updateFromServer(response) {
fluxDispatcher.dispatch({
type: "DATA_FROM_SERVER",
payload: {id: response.id, data: response}
});
}
// this handles the "DATA_FROM_SERVER" action
handleDataFromServer(action) {
this.cache[action.payload.id] = action.payload.data;
this.emit("change"); // or whatever you do to re-render your app
}
}
flux
、構築後にストアに注入されるため、initializeメソッドでアクションを取得する優れた方法はありません。Yahooの同形のフラックスライブラリから良いアイデアが見つかるかもしれません。これはFluxxor v2がより適切にサポートするものです。これについてチャットしたい場合は、遠慮なく私にメールしてください。
data: result
である必要がdata : data
ありますか?ありませんresult
。おそらく、データパラメータの名前をペイロードなどに変更することをお勧めします。
このブログ投稿はそれについて話し、Reactのブログで取り上げられました。
フロントエンドソフトウェアとバックエンドとの同期はまだ苦痛であるため、これはまだ明確に回答されていない非常に重要で難しい質問だと思います。
JSXコンポーネントでAPIリクエストを行う必要がありますか?店舗?別の場所?
ストアでリクエストを実行すると、2つのストアが特定のアクションに対して同じデータを必要とする場合、2つの同様の要求が発行されます(ストア間の依存関係を導入しない限り、私は本当に気に入らない)
私の場合、次の理由により、Qの約束をアクションのペイロードとして配置するのに非常に便利です。
Ajaxは悪
Ajaxは、推論するのが非常に難しいため、近い将来使用されることが少なくなると思います。正しい方法?デバイスを分散システムの一部と見なしているので、このアイデアに最初に出会った場所はわかりません(おそらく、この刺激的なChris Grangerビデオで)。
それについて考えてください。スケーラビリティのために、ストレージエンジンとして結果整合性を備えた分散システムを使用します(CAPの定理に勝ることはできず、多くの場合、利用可能にしたいためです)。これらのシステムは、相互にポーリングすることで同期しません(コンセンサス操作を除く)?ではなく、CRDTやイベントログなどの構造を使用して、分散システムのすべてのメンバーを最終的に整合させます(十分な時間が与えられれば、メンバーは同じデータに収束します) 。
次に、モバイルデバイスまたはブラウザとは何かについて考えます。これは、ネットワークレイテンシとネットワーク分割に悩まされる可能性がある分散システムのメンバーにすぎません。(つまり、地下鉄でスマートフォンを使用しています)
ネットワークパーティションとネットワークスピードトレラントデータベースを構築できる場合(つまり、孤立したノードへの書き込み操作を引き続き実行できることを意味します)、これらの概念にインスパイアされたフロントエンドソフトウェア(モバイルまたはデスクトップ)を構築できます。アプリのないボックスの機能は利用できません。
私たちは、データベースがフロントエンドアプリケーションを構築するためにどのように機能しているかに本当に刺激を与える必要があると思います。注目すべき点の1つは、これらのアプリがPOSTおよびPUTとGET ajaxリクエストを実行して互いにデータを送信するのではなく、イベントログとCRDTを使用して結果の一貫性を確保することです。
それで、なぜフロントエンドでそれをしないのですか?バックエンドはすでにその方向に進んでおり、Kafkaのようなツールは大規模なプレーヤーによって大規模に採用されています。これは何らかの形でイベントソーシング/ CQRS / DDDにも関連しています。
Kafkaの作者によるこれらの素晴らしい記事をチェックして、納得してください。
Ajaxリクエストを実行する代わりに、コマンドをサーバーに送信し、サーバーイベントのストリームを(たとえば、Webソケットを介して)受信することから始めることができます。
私はAjaxのリクエストにとても満足していません。Reactの開発者は関数型プログラマーである傾向があります。フロントエンドアプリケーションの「真の情報源」となるはずのローカルデータについて推論するのは難しいと思いますが、実際の真の情報源は実際にはサーバーデータベースにあり、「ローカル」の真実の情報源はすでに古くなっている可能性がありますあなたがそれを受け取ったとき、あなたがいくつかの不完全な更新ボタンを押さない限り、真の真の価値の源に決して収束しません...これはエンジニアリングですか?
しかし、いくつかの明らかな理由のために、そのようなものを設計することはまだ少し難しいです:
this.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
アクションクリエーターまたはストアのいずれかでデータを呼び出すことができます。重要なことは、応答を直接処理するのではなく、エラー/成功のコールバックでアクションを作成することです。ストアで直接応答を処理すると、設計がよりもろくなります。
私はFluxxor ajaxの例からBinary Museの例を使用しています。これは、同じアプローチを使用した私の非常に単純な例です。
単純な製品ストアにいくつかの製品アクションと、すべてが製品ストアに加えられた変更に応答するサブコンポーネントを持つコントローラービューコンポーネントがあります。たとえば、product-slider、product-list、product-searchコンポーネントです。
偽の製品クライアント
これは、製品を返す実際のエンドポイントを呼び出す代わりに使用できる偽のクライアントです。
var ProductClient = {
load: function(success, failure) {
setTimeout(function() {
var ITEMS = require('../data/product-data.js');
success(ITEMS);
}, 1000);
}
};
module.exports = ProductClient;
製品ストア
こちらがProduct Storeです。明らかにこれは非常に最小限のストアです。
var Fluxxor = require("fluxxor");
var store = Fluxxor.createStore({
initialize: function(options) {
this.productItems = [];
this.bindActions(
constants.LOAD_PRODUCTS_SUCCESS, this.onLoadSuccess,
constants.LOAD_PRODUCTS_FAIL, this.onLoadFail
);
},
onLoadSuccess: function(data) {
for(var i = 0; i < data.products.length; i++){
this.productItems.push(data.products[i]);
}
this.emit("change");
},
onLoadFail: function(error) {
console.log(error);
this.emit("change");
},
getState: function() {
return {
productItems: this.productItems
};
}
});
module.exports = store;
次に、AJAXリクエストを作成し、成功するとLOAD_PRODUCTS_SUCCESSアクションを起動して商品をストアに返す商品アクション。
製品のアクション
var ProductClient = require("../fake-clients/product-client");
var actions = {
loadProducts: function() {
ProductClient.load(function(products) {
this.dispatch(constants.LOAD_PRODUCTS_SUCCESS, {products: products});
}.bind(this), function(error) {
this.dispatch(constants.LOAD_PRODUCTS_FAIL, {error: error});
}.bind(this));
}
};
module.exports = actions;
したがってthis.getFlux().actions.productActions.loadProducts()
、このストアをリッスンしているコンポーネントから呼び出すと、製品がロードされます。
addProduct(id)
removeProduct(id)
同じパターンに従って、ユーザーの操作などに応答するさまざまなアクションがあると想像できます。
実装が少し難しいので、この例が少し役立つことを願っていますが、ストアを100%同期させるのに確かに役立ちました。
私はここで関連する質問に答えました:入れ子になったAPI呼び出しをフラックスで処理する方法
アクションは、変化を引き起こすものではありません。それらは、外界の変化をアプリケーションに通知し、その後アプリケーションがそのニュースに応答する新聞のようなものであることになっています。店はそれ自体に変化をもたらします。アクションはそれらに通知するだけです。
Fluxの作成者であるBill Fisher https://stackoverflow.com/a/26581808/4258088
基本的にあなたがしなければならないことは、アクションを介して必要なデータを述べることです。ストアがアクションによって通知を受けた場合、データをフェッチする必要があるかどうかを判断する必要があります。
ストアは、必要なすべてのデータを蓄積/フェッチする責任があります。ただし、ストアがデータを要求して応答を受け取った後は、ストアが直接応答を処理/保存するのではなく、フェッチしたデータを使用してアクション自体をトリガーする必要があることに注意してください。
店舗は次のようになります。
class DataStore {
constructor() {
this.data = [];
this.bindListeners({
handleDataNeeded: Action.DATA_NEEDED,
handleNewData: Action.NEW_DATA
});
}
handleDataNeeded(id) {
if(neededDataNotThereYet){
api.data.fetch(id, (err, res) => {
//Code
if(success){
Action.newData(payLoad);
}
}
}
}
handleNewData(data) {
//code that saves data and emit change
}
}
これが私の見解です:http : //www.thedreaming.org/2015/03/14/react-ajax/
お役に立てば幸いです。:)