Multiple Mostly-Independent Reducers #3152
Unanswered
skyler-cricut
asked this question in
Q&A
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Background
My team supports a large, growing application built primarily with TCA. Our team is composed of multiple sub-teams that work almost completely independently, where each one manages a specific domain in the application. TCA has supported us fairly well in this style of organization: each team owns a few Reducers which are included in the application's top-level Reducer. The entire app State and logic is essentially orchestrated through that single top-level Reducer.
We're now becoming increasingly interested in making our domain boundaries more formal and separated. Some of the reasons for this include:
Performance
We have some deeply-nested states that can send a lot of actions rapidly (e.g. scrolling tables of content). We've found that the performance of these pages is impacted by the number of ancestors they have in the Reducer tree, and how big those ancestors themselves are (i.e. how many action cases they switch over).
Stack Size
This discussion describes the problem: #2321. We've made aggressive use of COW wrappers, PresentationStates, etc. to work around these crashes, and they're not happening right now, but we have a lot of deeply-nested State, and we're not confident the app can continue to grow.
Simplicity / Reusability
We have some Store-driven Views that are commonly used throughout our application, and we're currently including the State for those common Views on every State for the Views that present them. In many cases, the presenting Views and Reducers are hardly interested in what the common View does—it would be fine if we could create those Views just like a
Text
or aButton
, with some simple configuration and some action handlers.Possible Solution - Feedback Wanted
One idea we've discussed is to start breaking our app into multiple "top-level" Reducers, so every action and state change doesn't go through a single Reducer. We don't want to do this too aggressively, since that would largely defeat the purpose of using TCA altogether, but there are a handful of boundaries we're identifying that could be good candidates for these kinds of breaks.
We don't know the best way to do this.
I've put together a small sample application that demonstrates how two independent Reducers might communicate through an interface defined in the View: IndependentReducers.zip
This mostly turned out pretty clean, but there's a couple of places where it's a bit rough, and I'm wondering if there's a better way to do it:
store
property in the child View can't just be alet
if some initialization parameters are required. The best I came up with was@State var store: Store
, with a manual initializer:_store = State(initialValue: ...)
.canBuyCadillacs
property in AssetsFeature.swift). Luckily, I think this would be uncommon, since the@Shared
macro would usually work well.I think it's also possible that some cross-boundary communication could go through some common Dependencies, but the interface becomes less clear at that point.
I would love feedback and suggestions!
Thank you in advance 🙏
Beta Was this translation helpful? Give feedback.
All reactions