Search code examples
design-patternsreduxreact-reduxflux

Redux build index of object


In a redux app lets say its a blog. State can look like

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

Now in a certain component I want to show all posts of a specific day, I can filter all posts using Array.filter to get posts of this day, but this mean that if I have 1000's of post every time component refresh it will recalculate whole filter.

So in such circumstances I think its better if I had an index in redux store something like

{
  PostsByDate: {
    '2017-03-13': [1,2], .. Etc
  }
}

So how to build such index and make sure that its always in sync with posts object ?


Solution

  • If you´re having a lot of data (+1000 blog posts) stored in the client side you might think about pagination and running the filter on the server side. The computational cost of the filter should be low, but it really depends on the type of filter you use, if you´re filtering using the body of every blog post most likely you´ll have performance issues. But if the cost of filtering is low, the cost of joining the array of ids with the complete collection of posts might be very similar, so there should´t be a significant performance gain with the architecture you´re proposing.

    That being said, I would do it by having inside an array the collection of post ids to show, and updating that array every time any filter changes. If there is no filter then the array is undefined and you show all the posts.

    action creator

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

    reducer

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

    container

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

    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
        }
      ...
    }
    

    Don't struggle with collections, use Immutable