mattkrick / meatier

:hamburger: like meteor, but meatier :hamburger:
3.05k stars 173 forks source link

Integrate react-redux-provide #66

Closed sompylasar closed 8 years ago

sompylasar commented 8 years ago

https://github.com/loggur/react-redux-provide

The architecture and its benefits are explained in this awesome article: https://medium.com/@timbur/react-automatic-redux-providers-and-replicators-c4e35a39f1

bartekus commented 8 years ago

From the initial look at the react-redux-provide is seems to me that a large redevelopment would be needed; furthermore another thing that is apparent is counter-ideology to the nature of redux by creation of more than one store. The structuring is also much different than the currently preferred redux so it seems that while it aims to alleviate the js fatigue, it will in the end add to it. While I'll be looking into it I'd say that currently the divergence between how things are done in react-redux community and this new way are much too broad to simply jump in without having a deeper understanding of all the pros and cons. However if you would like to go over the benefits in contract to meatier, and tackle the initial outline of the scope of action to take in the conversion, by all means do proceed.

mattkrick commented 8 years ago

@Bartekus thanks for digging into this, I was having trouble grokking this from the readme. I'm still thinking that a memorized reducer extended is the way to handle shared client server data and then allowing for vanilla redux api for local state, but im open

sompylasar commented 8 years ago

The core benefit is modularity, not only in React components, but in Redux logic. For large apps this is crucial, and Redux currently does not offer a solid solution.

The real-world problems are outlined in detail here: https://github.com/reactjs/react-redux/issues/278

mattkrick commented 8 years ago

@sompylasar maybe i'm not understanding the problem. Primarily, we're talking about instantiating multiple instances of a reducer, eg 3 identical counters with different state, right? Have you checked out https://github.com/erikras/multireducer? If there's something else I'm missing let me know, bonus points for real world examples!

sompylasar commented 8 years ago

Multireducer requires design-time structure of the app state with static reducer identifiers. In a large multi-component app there can be a requirement to instantiate "counters" (components) dynamically, each with its own startup options, own state controlled by a set of reducers, and actions targeted specifically at each instance, so that's not just React component reuse, but the whole ( view + state logic ) reuse.

mattkrick commented 8 years ago

so the use case is similar to http://erikras.github.io/redux-form/#/examples/dynamic?_k=5k6ex0?

sompylasar commented 8 years ago

Right, redux-form is the only component I know which provides reusable reducers. The reducer logic can be customized ( http://erikras.github.io/redux-form/#/api/reducer/normalize , http://erikras.github.io/redux-form/#/api/reducer/plugin ), but the customizations for each form should be written upfront, and passed during the app state construction -- they cannot be added dynamically without extra hacking, for example, if the form itself gets code-splitted away.

mattkrick commented 8 years ago

so assuming we've got a huge app & we piggyback on a bunch of form actions so we want to code-split those piggybacked reducers (eg the login function in that redux form plugin example). I could just say login: () => require('asyncModule'), right?

sompylasar commented 8 years ago

Sure, you could, but 1) you'll have to make it asynchronously, and this is a side-effect which must not be in a reducer, and 2) the "login:" has to be there always. Imagine you've got "login-abc", "login-def", "login-ghi" etc. dynamically generated forms, having these "abc", "def", "ghi" identifiers retrieved from a database in run time (actually, I've got other kind of components in mind, but forms will do for this example).

mattkrick commented 8 years ago

gotcha... so I think the underlying problem is currently redux has a global state (good!) and a global reducer (bad!). What'd be fun to play around with is doing away with reducers & replacing it with an API. For example, creating a store or adding a reducer gives you a store.actions.increase = [{fn1, 'counter1'}, {fn2, 'counter2'}]. The result of calling fn1 on counter1 is passed to counter2, etc, same as compose or a reduce function works. In doing so, you don't have to trust a 3rd party reducer because that reducer will only be called when needed. You can spec out an API description, etc similar to what GraphQL does right now, you have a predictable execution order (that you could declare), and you know who calls what. This would make debugging really easy, solve the problem you mentioned, plus the one here https://github.com/reactjs/redux/issues/1315#issuecomment-179164091.

sompylasar commented 8 years ago

Yes, global state is good, but the hardcoded structure is not so good in complex reuse cases. Of course, it should be hardcoded to certain extent to be testable, but it should be extendable and partially reusable. And yes, the Bounded Contexts concept of DDD, as well as Sagas, is definitely related.

I failed to understand this part of your comment:

For example, creating a store or adding a reducer gives you a store.actions.increase = [{fn1, 'counter1'}, {fn2, 'counter2'}]. The result of calling fn1 on counter1 is passed to counter2, etc, same as compose or a reduce function works. In doing so, you don't have to trust a 3rd party reducer because that reducer will only be called when needed.

The most clever idea I have seen for now remains the one with "provide".

mattkrick commented 8 years ago

i'll carve out some time & submit something on the redux repo over the next week or 2.

sompylasar commented 8 years ago

:+1: thanks for your input!

mattkrick commented 8 years ago

finally got around to a write up: https://medium.com/@matt.krick/solving-redux-s-shortcoming-in-150-locs-540979ce6cf9#.b9e0wvd21