Working with Data Structures #815

Closed
ronag opened this Issue Sep 28, 2015 · 8 comments

Comments

2 participants
@ronag

ronag commented Sep 28, 2015

We have gotten a bit stuck in using Redux in regards to modelling our data structures. We have started to have one core issue all over the place in different scenarios. This is related to reduxjs/reselect#47 and https://github.com/rackt/redux/issues/764. I will stop spamming this issue after this, apologies.

In our team we are a bit confused in regards to the data modelling in Redux. This might partly be because we come from a framework similar to Facebooks Relay. I haven't been able to find much mention about this anywhere else so maybe we are missing something fundamental?

In Redux we have a single application state tree, which is great. However, the documentation recommends that reducers use a flat data model/structure, which makes perfect sense and makes it easy to work with logic. There are even libraries such as normalizr that provide data in just the way we like it for out store logic.

The problem is that react-redux requires a "un-flat" data structure and we can find no pragmatic and performant way to achieve this. We've basically ended up with tree ways, neither one which we think is good.

  1. Use connect on all components so that they fetch the data they need, similar to Relay. This is not very pragmatic Redux as far as I understand.
  2. Create selectors that transform the flat data structure into a graph. This is has very bad performance since basically any change would cause the entire state graph to be rebuilt and react components updated (see, reduxjs/reselect#47).
  3. Model data as a tree in the reducer. This makes the logic complicated and slow, e.g. changing the selectedItems state in a list or a tree would require going through every item and setting selected=false and then find the correct item and set selected=true, which is O(n) instead of O(1) in a flat data structure. This also becomes even worse if you want to have a reference to the same item in several places (i.e. the whole point of having a flat data structure).

As an example (this is not exactly what we are doing) this is how we would like to model our data in our stores/reducers:

treeView: {
   root: 0,
   selected: [1],
   nodes: {
     0: { title: '0', children: [1, 2] },
     1: { title: '1' },
     2: { title: '2' }
   }
}

as opposed to:

treeView: {
  root: {
    title: '0',
    selected: false,
    children: {
      { title: '1', selected: true },
      { title: '2', selected: false }
    }
  }
}

@gaearon gaearon added the discussion label Sep 28, 2015

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 28, 2015

Collaborator

Use connect on all components so that they fetch the data they need, similar to Relay. This is not very pragmatic Redux as far as I understand.

I don't think it's a bad idea at all, if your data is very tree-ish. I think a sane solution is:

  • The component receives its own data via props
  • The component uses connect() to retrieve the data needed to render its children

This seems like a nice balance of component encapsulation, performance, and sanity.
What do you think?

Collaborator

gaearon commented Sep 28, 2015

Use connect on all components so that they fetch the data they need, similar to Relay. This is not very pragmatic Redux as far as I understand.

I don't think it's a bad idea at all, if your data is very tree-ish. I think a sane solution is:

  • The component receives its own data via props
  • The component uses connect() to retrieve the data needed to render its children

This seems like a nice balance of component encapsulation, performance, and sanity.
What do you think?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 28, 2015

Collaborator

See an example here (somewhat outdated and not Reduxy, but the idea is same): http://stackoverflow.com/a/25701169/458193

Collaborator

gaearon commented Sep 28, 2015

See an example here (somewhat outdated and not Reduxy, but the idea is same): http://stackoverflow.com/a/25701169/458193

@ronag

This comment has been minimized.

Show comment
Hide comment
@ronag

ronag Sep 28, 2015

Hm, yes that does seem like a good idea. The only thing I don't like about it is that one starts to mix smart and dumb components in different levels of the component tree.

ronag commented Sep 28, 2015

Hm, yes that does seem like a good idea. The only thing I don't like about it is that one starts to mix smart and dumb components in different levels of the component tree.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 28, 2015

Collaborator

That's the tradeoff. :-)

Collaborator

gaearon commented Sep 28, 2015

That's the tradeoff. :-)

@ronag

This comment has been minimized.

Show comment
Hide comment
@ronag

ronag Sep 28, 2015

Indeed, there are no unicorns unfortunately.

ronag commented Sep 28, 2015

Indeed, there are no unicorns unfortunately.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 28, 2015

Collaborator

To be fair I have found this to be a really nice compromise. You can always render parent with a non-store-derived data if you wish, but for the children it renders, you have to ensure the data is in store. On the other hand, those children can be used independently, and in this case, whoever uses them must provide their data.

Collaborator

gaearon commented Sep 28, 2015

To be fair I have found this to be a really nice compromise. You can always render parent with a non-store-derived data if you wish, but for the children it renders, you have to ensure the data is in store. On the other hand, those children can be used independently, and in this case, whoever uses them must provide their data.

@ronag

This comment has been minimized.

Show comment
Hide comment
@ronag

ronag Sep 28, 2015

Yes, that does sound quite reasonable. Could be a good example to mention in the advanced section of the documentation. If nobody else does it I'll try to get a PR done over the winter holidays.

Thanks for the feedback!

ronag commented Sep 28, 2015

Yes, that does sound quite reasonable. Could be a good example to mention in the advanced section of the documentation. If nobody else does it I'll try to get a PR done over the winter holidays.

Thanks for the feedback!

@ronag ronag closed this Sep 28, 2015

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 28, 2015

Collaborator

Yes, PR is definitely welcome—it's in the same scope as https://github.com/rackt/redux/issues/419.

Collaborator

gaearon commented Sep 28, 2015

Yes, PR is definitely welcome—it's in the same scope as https://github.com/rackt/redux/issues/419.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment