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

I've been struggling with where in component hierarchy I should read data from Stores.
I tried two extreme approaches, neither of which I quite liked:

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

Each component that needs some data from Store receives just entity ID and retrieves entity on its own.
For example, Article is passed articleId, UserAvatar and UserLink are passed 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个组件可能订阅store ,这令人沮丧;
  • 它是hard to keep track of how data is updated and in what order,因 for each 组件独立检索其数据;
  • 即使您可能有一个处于状态的实体,您也必须将其ID传递给子级,子级将再次检索它(否则会 destruct 一致性).

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

当我厌倦了追踪bug时,我试着将所有数据检索放在顶层.然而,事实证明这是不可能的,因为对于某些实体,我有几个层次的嵌套.

例如:

  • Category人中有UserAvatar人对该类别做出了贡献;
  • Article可能有几个Category.

因此,如果我想从Article级的存储中检索所有数据,我需要:

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

更令人沮丧的是,每当我需要一个深度嵌套的实体时,我都需要在每一层嵌套中添加代码来进一步传递它.

总结

这两种方法似乎都有缺陷.我怎样才能最优雅地解决这个问题?

我的目标:

  • store 不应该有疯狂的订户数量.如果父组件已经这样做了,那么每UserLink个都听UserStore是愚蠢的.

  • 如果父组件已从存储中检索到某个对象(例如user),我不希望任何嵌套组件必须再次检索它.我应该可以通过props 传递.

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

推荐答案

我采用的方法是让每个组件作为props 接收其数据(而不是ID).如果某个嵌套组件需要相关实体,则由父组件来检索它.

在我们的示例中,Article应该有一个articleprops ,它是一个对象(可能由ArticleListArticlePage检索).

因为Article还想为文章作者呈现UserLinkUserAvatar,所以它将订阅UserStore,并保持author: UserStore.get(article.authorId)的状态.然后,它将用这个this.state.author渲染UserLinkUserAvatar.如果他们想把它传下go ,他们可以.没有子组件需要再次检索此用户.

重申:

  • 没有组件将ID作为props 接收;所有组件都接收各自的对象.
  • 如果子组件需要实体,则父组件有责任检索实体并将其作为props 传递.

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

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

这会让最里面的组件变得愚蠢,但不会迫使我们将顶级组件复杂化.

Reactjs相关问答推荐

如何将google地址lat收件箱设置为输入值?

如何在Pivot模式下自定义标题?

CreateBrowserRouter将props 传递给父组件以验证权限

Tailwind不使用@apply classes构建,并强制使用类似于移动的viewport

无法在主组件的返回语句中呈现预期组件

如何在与AntD的react 中限制文件上传和显示消息?

如何使用.Aggregate从多个集合中获取数据,包括使用Mongoose+NextJS的SUM值

状态改变不会触发重新渲染

单击按钮不会切换组件(当按钮和组件位于两个单独的文件中时)

我从 S3 存储桶下载图像时收到错误

MERN,将动态列表中的元素插入数组

如何修改 react/jsx-no-useless-fragment 规则以允许 <>{children}

文本的几个词具有线性渐变 colored颜色 - React native

在 React JS 中编辑表格数据

React js中不记名令牌中的空间问题

导入样式化组件时未导入组件内容

如何从 graphql/apollo 中的缓存中清除多个查询

Cypress - 在继续之前等待下一个按钮重新出现

react 路由路由加载器不适用于嵌套组件

在 React 中使用使用状态挂钩合并两个数组