Redux构建对象索引

时间:2017-04-10 14:02:32

标签: design-patterns redux react-redux flux

在redux应用程序中,我们可以说它是一个博客。 州可以看起来像

{
  Posts: {
    1:{day:'2016-03-13', id:1},
    2:{day:'2016-03-14',id:2},
    .....
  }
}

现在在某个组件中我想显示特定日期的所有帖子,我可以使用Array.filter过滤所有帖子以获取当天的帖子,但这意味着如果我每次有组件刷新1000个帖子将重新计算整个过滤器。

所以在这种情况下,如果我在redux商店中有一个像

这样的索引,我认为它会更好
{
  PostsByDate: {
    '2017-03-13': [1,2], .. Etc
  }
}

那么如何构建这样的索引并确保它始终与posts对象同步?

2 个答案:

答案 0 :(得分:1)

如果您在客户端存储了大量数据(+1000篇博文),您可能会想到分页并在服务器端运行过滤器。过滤器的计算成本应该很低,但它实际上取决于您使用的过滤器类型,如果您使用每个博客文章的主体进行过滤,则很可能会出现性能问题。但是如果过滤成本很低,那么加入一系列id与完整帖子集合的成本可能非常相似,所以你建议的体系结构不应该有显着的性能提升。

话虽这么说,我会通过在数组内部显示post id的集合来实现它,并在每次过滤器更改时更新该数组。如果没有过滤器,则数组为undefined并显示所有帖子。

动作创建者

function filterPosts(filter) {
  return { type: "FILTER_POSTS", filter };
}

<强>减速器

switch (action.type) {
  ...
  case "FILTER_POSTS":
    return { 
      ...state, 
      PostsFiltered: action.filter 
        ? Posts.filter(action.filter).map(p => p.id)
        : undefined 
    };
  ...
}

<强>容器

container = connect(
  state => ({ ... }), 
  dispatch => bindActionCreators({
    onFilter: filterPosts,
    onRemoveFilter: filterPosts.bind(null, undefined)
  }, dispatch)
)(Component);

<强>组件

filter() {
  // Use whatever filter you want here
  this.props.onFilter(...);
}
removeFilter() {
  this.props.onRemoveFilter();
}
render() {
  ...
    {
      this.props.postsFiltered 
        ? this.props.posts.filter(p => this.props.postsFiltered.contains(p.id))
        : this.props.posts
    }
  ...
}

不要对收藏品感到困扰,请使用Immutable

答案 1 :(得分:1)

官方redux文档中建议的一件事是为您的数据构建索引。我收集状态的最小结构是

Map({
  byId: Map(),
  allIds: List([])
})

其中byId地图基本上是您在Posts哈希中的内容。把你的redux商店想象成一个客户端数据库,如果你至少有一些后端体验IMO,这种思维模式真的很有帮助。按键查询映射是O(1)操作,因此这为您提供了id的快速提取(想想SELECT * FROM POSTS WHERE id = your_id LIMIT 1)。

现在,allIds只是byId中所有ID的列表,在显示数据列表时非常有用 - 列表组件只有id列表,并将每个id传递给子{{1}组件,它们也连接到redux存储并使用简单选择器ListItemmapStateToProps函数中获取单个项目。selectPost(state, postId) { return state.posts.getIn(['byId', postId]) }

这为您带来了巨大的性能提升,特别是如果PostsList组件使用重新选择函数来缓存获取ID列表,因为如果您重新排序集合,React会使用key道具以智能方式处理它,在你的情况下应该是post id - 所以rerender非常快。如果某些帖子发生了变化,只需要重新渲染这个单独的帖子组件。

您可以通过为特定用例引入额外索引来进一步采用此方法:如果您希望显示某些用户的所有帖子,则可以添加byUserId: Map(<lists of post ids>)以便在这种情况下更快地查找。与关系数据库索引完全相同,它的概念相同。

在rails中,每个模型都有updated_at时间戳字段,因此简单的缓存可以检查后端上获取的集合的最新updated_at,并将其与标头进行比较,客户端可以将其与所有api请求一起发送,如果它晚于客户端值然后客户端数据不是陈旧的,后端可以立即响应相应的头,响应时间为2-5毫秒,然后客户端可以完全绕过抓取json,解析它并提供给reducer函数,所以很多客户也有性能提升。这样你的组件就可以在没有任何复杂逻辑的情况下触发componentDidMount上的api请求,缓存层将处理其余的