Centralize Reducer.body Scope
object and Store.scope
into one object
#1718
Replies: 2 comments 9 replies
-
This makes sens only in very simples cases. Here are my 2c why. Scoping at the view level is used to control how often a view rerenders and so should be scoped as narrow as possible while scoping at the reducer level allows composition and reuse of logic. Lets say you build some kind of form, you could have a reducer per field, a reducer for validation etc while at the view level you could have a single viewstore. Disregarding my example I‘d expect to have far more viewstore scoping than reducer scoping especially when working with collections where you want to be precise about view rendering. Obviously how you split your features is deeply connected to what you want to achieve so take my comment with a grain of salt. |
Beta Was this translation helpful? Give feedback.
-
Can you share a full, building example of this? I'm having a hard time understanding how a parent reducer would succeed to build with a child embedded in it without the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Intro
I'm fairly new to TCA, but have run into a pain point that I think is largely solvable (assuming my pain point is not due to a misunderstanding):
State
into anotherState
requires 2 separateScope
calls (one of which takes aCasePath
, the other taking a closure/enum case):Scope(...)
(takes aCasePath
)NewView(store: store.scope(...)
(takes a(ChildAction) -> Action
- i.e. an enum case)Problem:
Reduce
to anotherReducer
) in one place then we should be able to leverage that logic elsewhere when needed.Scope
object to myReducer.body
variable. Debugging this mistake is PAINFULL. Everything builds and runs, but suddenly things just don't work as expected... Bindings don't get updated at all, buttons don't trigger navigation like they're setup to, etc. You get the purple warnings, but those can be missed if you're not looking for them.Suggested Solution:
I believe we can improve the current solution by slightly altering the
Scope
object (or in my code example below create aSafeScope
wrapper around it) and adding aStore.scope
function that takes aSafeScope
object.##Code:
Implementation Code
The above change allows for the following implementation, which I think is preferable to the way I was doing it (assuming I was doing it correctly):
Caveat: the code below was typed in-browser, so it's not compiler guaranteed...
Then the View can re-use that scope:
Potential Problems:
Dependency
s into the scoped Reducers, but might break down if you need to initialize your Scoped reducer with some value... i.e. -static let reducer2: ScopeOf<Reducer2> = .init(...) { Reducer2(someValue: <what do we put here?>, ...)
struct
in both sides of the scoping, which is not always true. So this may break down with different forms ofState
orAction
.Potential Awesomeness:
Scope
s being defined on the Reducer type, there might be a possibility of creating an auto-implementedvar scopes
on the ReducerProtocol that uses reflection or something to grab the scopes defined on itself and inject them into thebody
automagically. That would mean you wouldn't need to "add" the scopes anywhere in the Reducer besides declaring them (in a specific place).ScopeOf
variable declarations were instance variables instead of static variables as I have it written above),Store
could implementdynamicMemberLookup
to theReducer
type and allow syntax like:View2(store: store.reducer2)
(whereReducer1
has an instance variable ofvar reducer2: ScopeOf<Reducer2> = .init....
Outro
I'd love feedback on this idea.
Firstly, are my assumptions/understandings of the requirements of TCA off? Does something like this already exist that I just don't know about?
If you're using TCA differently from the above examples, would the above code break you?
Would it benefit you? If not, are there alterations of it that it could benefit your usage of TCA?
Beta Was this translation helpful? Give feedback.
All reactions