[解決済み] FluxのStoreからコンポーネントはどの入れ子レベルでエンティティを読み込むべきですか?
質問
Fluxを使用するためにアプリを書き換えているのですが、Storeからのデータ取得に問題があります。たくさんのコンポーネントがあり、それらはたくさんネストしています。そのうちのいくつかは、大きな (
Article
)、小さくてシンプルなもの(
UserAvatar
,
UserLink
).
Storesからデータを読み取るのに、コンポーネント階層のどこで読み取ればいいのか悩んでいます。
私は 2 つの極端なアプローチを試しましたが、どちらもあまり好きではありませんでした。
すべてのエンティティ コンポーネントが自分自身のデータを読み取る
Storeから何らかのデータを必要とする各コンポーネントは、エンティティIDだけを受け取り、自分自身でエンティティを取得します。
例えば
Article
が渡される
articleId
,
UserAvatar
と
UserLink
が渡される
userId
.
この方法にはいくつかの重大な欠点があります(コードサンプルのところで説明します)。
var Article = React.createClass({
mixins: [createStoreMixin(ArticleStore)],
propTypes: {
articleId: PropTypes.number.isRequired
},
getStateFromStores() {
return {
article: ArticleStore.get(this.props.articleId);
}
},
render() {
var article = this.state.article,
userId = article.userId;
return (
<div>
<UserLink userId={userId}>
<UserAvatar userId={userId} />
</UserLink>
<h1>{article.title}</h1>
<p>{article.text}</p>
<p>Read more by <UserLink userId={userId} />.</p>
</div>
)
}
});
var UserAvatar = React.createClass({
mixins: [createStoreMixin(UserStore)],
propTypes: {
userId: PropTypes.number.isRequired
},
getStateFromStores() {
return {
user: UserStore.get(this.props.userId);
}
},
render() {
var user = this.state.user;
return (
<img src={user.thumbnailUrl} />
)
}
});
var UserLink = React.createClass({
mixins: [createStoreMixin(UserStore)],
propTypes: {
userId: PropTypes.number.isRequired
},
getStateFromStores() {
return {
user: UserStore.get(this.props.userId);
}
},
render() {
var user = this.state.user;
return (
<Link to='user' params={{ userId: this.props.userId }}>
{this.props.children || user.name}
</Link>
)
}
});
この方法の欠点
- 100 個ものコンポーネントが Stores にサブスクライブしている可能性があるのは不満です。
- それは どのようにデータが更新され、どのような順序で更新されるかを追跡するのは難しい。 というのも、各コンポーネントが独立してデータを取得するからです。
- たとえ はすでに が状態であっても、その ID を子へ渡すことを余儀なくされ、子はそれを再び取得します (さもなければ整合性が失われます)。
すべてのデータはトップレベルで一度読み込まれ、コンポーネントに渡される
バグを追跡するのに疲れたとき、私はすべてのデータ取得をトップレベルに置くことを試みました。しかし、いくつかのエンティティにはいくつかのレベルのネストがあるため、これは不可能であることがわかりました。
たとえば
-
A
Category
にはUserAvatar
を含む。 -
について
Article
は、複数のCategory
s.
したがって、もし私がStoreからすべてのデータを
Article
のレベルでStoreからすべてのデータを取得したい場合、私は必要でしょう。
-
から記事を取得する。
ArticleStore
; -
全ての記事のカテゴリを
CategoryStore
; -
各カテゴリの投稿者を個別に
UserStore
; - どうにかして、すべてのデータをコンポーネントに渡します。
さらに不満なのは、深くネストされたエンティティが必要なときはいつでも、さらにそれを下に渡すために、ネストの各レベルにコードを追加する必要があったことです。
まとめ
どちらのアプローチも欠陥があるように見えます。どうすれば最もエレガントにこの問題を解決できるでしょうか?
私の目標
-
店舗は、非常識な数の購読者を持つべきではありません。それは、それぞれの
UserLink
をリッスンするためにUserStore
をリッスンします。 -
親コンポーネントがストアから何らかのオブジェクトを取得した場合(例えば
user
のように)、ネストされたコンポーネントが再びそれを取得する必要がないようにしたいです。私はそれをプロップス経由で渡すことができるはずです。 -
関係の追加や削除が複雑になるので、トップレベルですべてのエンティティ(関係を含む)をフェッチする必要はないはずです。ネストされたエンティティが新しいリレーションシップを取得するたびに、すべてのネストレベルで新しいプロップを導入したくありません (たとえば、カテゴリが
curator
).
どのように解決するのですか?
私がたどり着いたアプローチは、各コンポーネントにそのデータ(IDではない)をpropとして受け取らせることです。ネストされたコンポーネントが関連するエンティティを必要とする場合、それを取得するのは親コンポーネント次第です。
私たちの例では
Article
には
article
プロップはオブジェクトである (おそらく
ArticleList
または
ArticlePage
).
なぜなら
Article
もレンダリングしたいからです。
UserLink
と
UserAvatar
を登録すると、記事の著者のために
UserStore
を購読し
author: UserStore.get(article.authorId)
をその状態のままにしておきます。その後、レンダリングされる
UserLink
と
UserAvatar
を、この
this.state.author
. もし、このユーザーをさらに引き継ぎたい場合は、引き継ぐことができます。子コンポーネントがこのユーザーを再び取得する必要はありません。
繰り返しになりますが
- どのコンポーネントもIDをpropとして受け取ることはなく、すべてのコンポーネントはそれぞれのオブジェクトを受け取ります。
- 子コンポーネントがエンティティを必要とする場合、親の責任でそれを取得し、propとして渡します。
これは私の問題をうまく解決してくれました。この方法を使うためにコード例を書き直しました。
var Article = React.createClass({
mixins: [createStoreMixin(UserStore)],
propTypes: {
article: PropTypes.object.isRequired
},
getStateFromStores() {
return {
author: UserStore.get(this.props.article.authorId);
}
},
render() {
var article = this.props.article,
author = this.state.author;
return (
<div>
<UserLink user={author}>
<UserAvatar user={author} />
</UserLink>
<h1>{article.title}</h1>
<p>{article.text}</p>
<p>Read more by <UserLink user={author} />.</p>
</div>
)
}
});
var UserAvatar = React.createClass({
propTypes: {
user: PropTypes.object.isRequired
},
render() {
var user = this.props.user;
return (
<img src={user.thumbnailUrl} />
)
}
});
var UserLink = React.createClass({
propTypes: {
user: PropTypes.object.isRequired
},
render() {
var user = this.props.user;
return (
<Link to='user' params={{ userId: this.props.user.id }}>
{this.props.children || user.name}
</Link>
)
}
});
これにより、最内部のコンポーネントは愚かなままですが、トップレベルのコンポーネントを地獄のように複雑にすることを強制されません。
関連
-
[解決済み] <Enter>でjQuery UIダイアログを送信する
-
[解決済み] TypeScriptのdeclare classとinterfaceの違いとは?
-
[解決済み] オブジェクトの配列からReactコンポーネントをレンダリングする
-
[解決済み] jQueryの$という記号の意味は何ですか?
-
[解決済み] コールバック地獄とは何か、RXはそれをどのように、そしてなぜ解決するのか?
-
[解決済み] react-routerのハッシュフラグメントからクエリパラメータを取得する
-
[解決済み] ECMAScriptとは?
-
[解決済み] CORS: 認証モードは 'include' です。
-
[解決済み] jQueryのバージョン1、バージョン2、バージョン3の違いは何ですか?[クローズド]
-
[解決済み] フラックスストアとアクション、どちらを外部サービスに接触させるべきか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] ジェスト あるクラスの特定のメソッドをモックする方法
-
[解決済み] Javascriptによるタッチスクリーンデバイスの検出
-
[解決済み] javascriptで2つの数値を連結する方法は?
-
[解決済み] bootstrap のポップオーバーがすべての要素の上に表示されない
-
[解決済み] Chart.jsを使ってドーナツチャートの中にテキストを追加するには?
-
[解決済み] Javascriptで動的に命名されたメソッドを呼び出すにはどうすればよいですか?
-
[解決済み] TypeScriptプロジェクトで既存のC#クラス定義を再利用する方法
-
[解決済み] Prototypeを使ってtextareaを自動サイズ調整するには?
-
[解決済み] なぜjavascriptのES6 Promisesはresolve後も実行を継続するのですか?
-
[解決済み] V8 Javascript エンジンのスタンドアロン実行