我正在重写我的应用程序以使用Flux,但是从商店检索数据时遇到问题。我有很多组件,它们嵌套很多。其中有些是大(Article),有些是小而简单(UserAvatar,UserLink)。
Article
UserAvatar
UserLink
我一直在努力从组件存储层次结构中读取数据。 我尝试了两种极端的方法,但我都不喜欢:
需要从Store获得一些数据的每个组件仅接收实体ID,并自行检索实体。 例如,Article被传递articleId,UserAvatar并UserLink传递userId。
articleId
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> ) } });
这种方法的缺点:
当我厌倦了跟踪错误时,我试图将所有检索数据放在顶层。但是,事实证明这是不可能的,因为对于某些实体,我具有多个层次的嵌套。
例如:
Category
因此,如果我想以的级别从商店中检索所有数据,则Article需要:
ArticleStore
CategoryStore
UserStore
更令人沮丧的是,每当我需要一个深度嵌套的实体时,我都需要向每个嵌套级别添加代码,以附加地传递它。
两种方法似乎都有缺陷。如何最优雅地解决这个问题?
我的目标:
商店不应有疯狂的订户数量。如果父组件已经这样做,每个UserLink人都听不懂UserStore。
如果父组件已从存储中检索到某个对象(例如user),则我不希望任何嵌套的组件都必须再次获取它。我应该能够通过道具传递它。
user
我不必在顶层获取所有实体(包括关系),因为这会使添加或删除关系复杂化。我不想每次嵌套实体获得新关系(例如category获得curator)时都在所有嵌套级别引入新道具。
curator
我到达的方法是让每个组件都以道具的形式接收其数据(而不是ID)。如果某些嵌套组件需要相关实体,则取决于父组件来检索它。
在我们的示例中,Article应该有一个articleprop,它是一个对象(大概由ArticleList或检索ArticlePage)。
article
ArticleList
ArticlePage
因为Article也要渲染UserLink并UserAvatar为文章的作者,它将订阅UserStore并保持author: UserStore.get(article.authorId)其状态。然后它将渲染UserLink并UserAvatar带有this this.state.author。如果他们希望进一步传递下去,可以。没有子组件将需要再次检索该用户。
author: UserStore.get(article.authorId)
this.state.author
重申:
这很好地解决了我的问题。使用此方法重写的代码示例:
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> ) } });
这使最里面的组件保持愚蠢,但不会迫使我们使顶级组件复杂化。