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):
Stateinto anotherStaterequires 2 separateScopecalls (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:
Reduceto anotherReducer) in one place then we should be able to leverage that logic elsewhere when needed.Scopeobject to myReducer.bodyvariable. 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
Scopeobject (or in my code example below create aSafeScopewrapper around it) and adding aStore.scopefunction that takes aSafeScopeobject.##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:
Dependencys 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?>, ...)structin both sides of the scoping, which is not always true. So this may break down with different forms ofStateorAction.Potential Awesomeness:
Scopes being defined on the Reducer type, there might be a possibility of creating an auto-implementedvar scopeson the ReducerProtocol that uses reflection or something to grab the scopes defined on itself and inject them into thebodyautomagically. That would mean you wouldn't need to "add" the scopes anywhere in the Reducer besides declaring them (in a specific place).ScopeOfvariable declarations were instance variables instead of static variables as I have it written above),Storecould implementdynamicMemberLookupto theReducertype and allow syntax like:View2(store: store.reducer2)(whereReducer1has 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