小编典典

组件应在什么嵌套级别从Flux商店读取实体?

reactjs

我正在重写我的应用程序以使用Flux,但是从商店检索数据时遇到问题。我有很多组件,它们嵌套很多。其中有些是大(Article),有些是小而简单(UserAvatarUserLink)。

我一直在努力从组件存储层次结构中读取数据。
我尝试了两种极端的方法,但我都不喜欢:

所有实体组件都读取自己的数据

需要从Store获得一些数据的每个组件仅接收实体ID,并自行检索实体。
例如,Article被传递articleIdUserAvatarUserLink传递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多个组件可能会订阅商店。
  • 由于每个组件都是独立检索数据的,因此 很难跟踪数据的更新方式和顺序
  • 即使您可能 已经 有一个实体处于状态,您还是被迫将其ID传递给子代,子代将再次检索它(或破坏一致性)。

所有数据在顶层都读取一次,然后传递给组件

当我厌倦了跟踪错误时,我试图将所有检索数据放在顶层。但是,事实证明这是不可能的,因为对于某些实体,我具有多个层次的嵌套。

例如:

  • 一个Category包含UserAvatar的谁该类别有助于人们的;
  • 一个Article可能有几个Category秒。

因此,如果我想以的级别从商店中检索所有数据,则Article需要:

  • 从中检索文章ArticleStore;
  • CategoryStore; 检索所有文章类别。
  • 从中分别检索每个类别的贡献者UserStore
  • 以某种方式将所有数据传递到组件。

更令人沮丧的是,每当我需要一个深度嵌套的实体时,我都需要向每个嵌套级别添加代码,以附加地传递它。

加起来

两种方法似乎都有缺陷。如何最优雅地解决这个问题?

我的目标:

  • 商店不应有疯狂的订户数量。如果父组件已经这样做,每个UserLink人都听不懂UserStore

  • 如果父组件已从存储中检索到某个对象(例如user),则我不希望任何嵌套的组件都必须再次获取它。我应该能够通过道具传递它。

  • 我不必在顶层获取所有实体(包括关系),因为这会使添加或删除关系复杂化。我不想每次嵌套实体获得新关系(例如category获得curator)时都在所有嵌套级别引入新道具。


阅读 308

收藏
2020-07-22

共1个答案

小编典典

我到达的方法是让每个组件都以道具的形式接收其数据(而不是ID)。如果某些嵌套组件需要相关实体,则取决于父组件来检索它。

在我们的示例中,Article应该有一个articleprop,它是一个对象(大概由ArticleList或检索ArticlePage)。

因为Article也要渲染UserLinkUserAvatar为文章的作者,它将订阅UserStore并保持author: UserStore.get(article.authorId)其状态。然后它将渲染UserLinkUserAvatar带有this
this.state.author。如果他们希望进一步传递下去,可以。没有子组件将需要再次检索该用户。

重申:

  • 没有组件会收到ID作为道具。所有组件都接收各自的对象。
  • 如果子级组件需要一个实体,则由父级负责检索它并作为道具传递。

这很好地解决了我的问题。使用此方法重写的代码示例:

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>
    )
  }
});

这使最里面的组件保持愚蠢,但不会迫使我们使顶级组件复杂化。

2020-07-22