-
Notifications
You must be signed in to change notification settings - Fork 33
Discussion: Scoping via function composition vs. scope as a delimited string or array #32
Comments
Discussion continuing from here (I'm busy at the moment, but I'll try to put some thoughts down tonight) |
Got some time... here we go... For me, when it comes to isolating the sub-store from the root store (which is the primary focus of redux-subspace), the prefixing approach has an incredible advantage over a For example given a reducer (from the redux docs):
This will already ignore a If the It boils down it being implicit or explicit when dealing with the larger redux eco-system. The prefix approach will be implicitly included/excluded from anything looking at action types, while the When it comes to
I will concede that a common pattern I see (even if the examples and docs or this repo) is:
Currently, If it did that, there actually isn't that much difference then from a consumer's perspective to the
An Does all this make sense? |
Ah, I should have been more clear! The two approaches I described both prefix the action type field. The difference between them is how they track their position in the tree. When dispatch fires on either approach though, the result will be identical prefixed actions. |
Then I don't actually follow how your alternative proposition works... Can you run through a basic process flow of an action that is dispatched from two layers deep? |
It is important to support the scenario where both global and local state and/or actions are needed in the component or subcomponents – as transparently and hassle-free as possible. I would rather supply a helper or path (a lens, optimally) for the component to work with than doing things automatically. |
@mpeyper, I edited my original comment above. |
Good chance you folks have seen this already, but just in case: the main place for prior discussions regarding encapsulation approaches is https://github.com/slorber/scalable-frontend-with-elm-or-redux . May be useful stuff you can reference there. I also have some related articles in the Redux Architecture#Encapsulation section of my links list. I haven't dug much further into this particular topic myself beyond cataloging things, but it's a discussion I'm interested in. |
@dalgard how does a lens differ from a selector (which is all |
@jcheroske was the For the record, redux-subspace is not quite doing either approach. A simplified version is more like
As I previously mentioned, If you add in my proposition in #31, it will look something like:
As a side note, does |
Note to self: writing code in the airport is questionable at best. Yes, and it was supposed to dispatch off the original store. And the
Man, I could have sworn I tested that just the other day, just for yucks. But, nope, no dice there. I always use lodash for that kind of thing anyway, and that's what I did just now.
I think, imho, that you're doing the first approach pretty much, no? Composing calls to the store as you become more deeply nested vs always calling back to the root. I see you've broken out the state retrieval via a mapper, but the mapper calls the previous level's store. And I see you're passing down the fully qualified scope, but you don't really use it in that code. |
@mpeyper A lens doesn't really differ from a selector when only using it to view data (selector = view(myLens) <-- curried). I simply think lenses is a better API in general, if used consistently within a domain. |
I'd say the main differences between a "lens" and a "selector" is that (from my very limited knowledge) a lens is generally an abstraction over looking up data from a very specific state path (and also potentially applying updates to that same state path). A selector, on the other hand, normally takes |
The reason I asked the question originally has to do with making redux namespacing work with the various side-effect libraries. The way I did it was to remove the scope from the action type as it was passed to the epic, and then apply the scope to any actions emitted. So the epic was listening for global actions, and a wrapper was globalizing incoming actions and re-scoping outgoing actions. It works, but I'm very curious if people are adding and removing scoped sagas, epics or whatever as the corresponding component is mounted and unmounted? |
@dalgard @markerikson so @jcheroske middleware that runs outside of the component (like sagas - I don't know enough about epics to say whether the do or not) cause an interesting problem for How this was solved for sagas was to essentially create a seperate saga context for the subspaced saga, but it has to be wrapped separately from the component as it doesn't actually originate from within it (you can take a look at my proof of concept for #18 here). Speaking more generally, wrapping your thing (action, reducer, component, saga, epic, thunk, logic, etc) to remove the namespace on the way in, and attach it on any thing on the way out is my preferred approach. Elevating the thing to global scope will likely come back to bite you in unexpected ways. |
I guess I didn't mean that the 'thing' was listening to global actions. More that the actions it was listening for were un-scoped, but local. Just like in subspace where a reducer would be written to listen to a global action ( This is essentially what I had to do to get epics working, except for the fact that you never call dispatch directly within an epic. An epic is just an observable stream that has actions as input and actions as output. All outputted actions will be dispatched for you. I wrote a wrapper that stripped off the scope of all inputted actions, and put it back on anything coming out. So I'm assuming you install your sagas at application startup, just like most folks install regular sagas? No fancy install/uninstall? |
No, nothing fancy. The top level saga must be wrapped in a store provider to get the root store into the saga's context, but other than that they are treated like normal sagas. I'd love to see your epics solution. I haven't looked at them at all (they are a concept fro redux-observable right?), so it would be good to see something from someone more familiar with them. |
My approach was to include additional info in the action, that would then be used by a small wrapper around an epic-like observable. I added the scope, the un-scoped action type, and a scoped Here is my
|
mapState is now optional: default to `(state) => state[namespace]` (from ioof-holdings#32)
I can see two ways of tracking the subspacing in the component tree. Both involve altering the redux store provided in the context. The first approach uses function composition, while the second uses a scope string or array.
I think one of the challenges for us, as we discuss these concepts, is finding the language for things. Perhaps we should start another discussion about names?
First approach:
Second approach:
Each of these approaches works fine for state scoping and action prefixing. I'm curious what pros and cons of each approach people see. I see a clear winner when it comes to supporting middleware, but let's begin the discussion with the more general case.
The text was updated successfully, but these errors were encountered: