Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working with Data Structures #815

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

Working with Data Structures #815

ronag opened this issue Sep 28, 2015 · 8 comments

Comments

@ronag
Copy link

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 #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, Memoizing Hierarchial Selectors  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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

gaearon commented Sep 28, 2015

That's the tradeoff. :-)

@ronag
Copy link
Author

ronag commented Sep 28, 2015

Indeed, there are no unicorns unfortunately.

@gaearon
Copy link
Contributor

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
Copy link
Author

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 as completed Sep 28, 2015
@gaearon
Copy link
Contributor

gaearon commented Sep 28, 2015

Yes, PR is definitely welcome—it's in the same scope as #419.

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

No branches or pull requests

2 participants