我正在重写我的应用程序以使用Flux,但从商店检索数据时遇到问题。我有很多组件,它们嵌套很多。其中有些是大(Article
),有些是小而简单(UserAvatar
,UserLink
)。
我一直在努力在组件层次结构中的哪些位置应该从商店读取数据。
我尝试了两种极端的方法,但我都不喜欢:
所有实体组件都读取自己的数据
需要从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>
)
}
});
这种方法的缺点:
- It's frustrating to have 100s components potentially subscribing to Stores;
- It's hard to keep track of how data is updated and in what order because each component retrieves its data independently;
- Even though you might already have an entity in state, you are forced to pass its ID to children, who will retrieve it again (or else break the consistency).
All data is read once at the top level and passed down to components
When I was tired of tracking down bugs, I tried to put all data retrieving at the top level. This, however, proved impossible because for some entities I have several levels of nesting.
For example:
- A
Category
containsUserAvatar
s of people who contribute to that category; - An
Article
may have severalCategory
s.
Therefore if I wanted to retrieve all data from Stores at the level of an Article
, I would need to:
- Retrieve article from
ArticleStore
; - Retrieve all article's categories from
CategoryStore
; - Separately retrieve each category's contributors from
UserStore
; - Somehow pass all that data down to components.
Even more frustratingly, whenever I need a deeply nested entity, I would need to add code to each level of nesting to additionally pass it down.
Summing Up
Both approaches seem flawed. How do I solve this problem most elegantly?
My objectives:
Stores shouldn't have an insane number of subscribers. It's stupid for each
UserLink
to listen toUserStore
if parent components already do that.如果父组件已经从存储中检索到某个对象(例如
user
),我不希望任何嵌套的组件都必须再次获取它。我应该能够通过道具传递它。我不必在顶层获取所有实体(包括关系),因为这会使添加或删除关系复杂化。我不想每次嵌套实体获得新关系(例如category获得
curator
)时都在所有嵌套级别引入新道具。
我的解决方案要简单得多。每个具有自己状态的组件都可以交谈和收听商店。这些是非常类似于控制器的组件。不允许嵌套更深层的嵌套组件,这些组件不能保持状态,而只能渲染内容。他们仅收到用于纯渲染的道具,非常类似于视图。
这样,一切都从有状态组件流入无状态组件。保持状态计数低。
在您的情况下,Article将是有状态的,因此仅与商店和UserLink等进行对话,因此它将接收article.user作为道具。