I've really enjoyed watching (then rewatching portions of) the video series as I put it into practice in a sample app of my own. I really like the idea of SCA (or is it TCA?) and I think I finally grok things well enough to start asking questions.
One struggle I have is that the idea of maintaining all the UI state and actions at the root level feels wrong. Wouldn't there be an occasion to hide temporary state or local actions so that they don't leak from the lower level to the highest level?
My initial thoughts (in order of likelihood to me):
I am missing something fundamental
The examples are overly simplified for the same of demonstration
The intent is just that: references to everything will live at the root
I would appreciate any pointers to blog articles, sections of existing videos or articles, or anything that helps me understand better.
Hi @dwsjoquist! How do you think, maybe it's that you are looking for?
struct ViewState: Equatable {
var alertData: AlertData?
var code: String
var isActivityIndicatorVisible: Bool
var isFormDisabled: Bool
var isSubmitButtonDisabled: Bool
}
enum ViewAction {
case alertDismissed
case codeChanged(String)
case submitButtonTapped
}
let store: Store<TwoFactorState, TwoFactorAction>
public init(store: Store<TwoFactorState, TwoFactorAction>) {
self.store = store
}
public var body: some View {
WithViewStore(self.store.scope(state: { $0.view }, action: TwoFactorAction.view)) { viewStore in
Yes and no, I guess. Usually you separate your app to several modules, you could do it even with a small pieces as it was shown in todo app example. And you map your view actions to the actions of this tiny module, not to the AppEvent.
With ViewState it’s even easier ViewState it’s mapped version of business logic State for easier representation on the view module. Sometimes I put some constant data in ViewState as well, such as scene title or colors
To communicate between modules, you have to write a parser from one action to another. But, essentially, these modules are separated.
In each module you have to write a basic view model or view state or whatever which could handle input and output of events/actions.
And on AppLevel (as someone said) you could keep every module.
enum CustomModule {
// define MainViewModel which will keep state.
class Assembly {
var mainViewModel: MainViewModel
// subscribe on output publisher to receive events from views of this module.
var outputPublisher: AnyPublisher<ViewAction, Never> { self.mainViewModel.outputActionPublisher }
// send input events into this stream
var inputSubject: PassthroughSubject<InputAction, Never> { self.mainViewModel.inputSubject }
}
}
@dwsjoquist the SCA is based around the idea that you represent your view state as a state machine with the reducer specifying transitions between valid states.
Which requires every view action to be mapped to a higher level action, all the way back to the root level (AppAction/AppState), right?
I'm having a little trouble understanding what your concern is exactly, is it simply that there's some boilerplate involved in mapping the state/actions up to the root level or is it something to do with controlling access to the information?
No serious concerns, just trying to understand the flavor of the architecture.
The last few years I've been working on several very large scale applications with multiple modules -- each of which manages its own state/actions. The very top level of the app is effectively a module integration layer that creates containers for the other modules to live in.
Each module's internals are private (at least the newer ones) and provide observables to other modules as needed as part of their API/contract for the outside world.
Mostly I'm trying to draw correlations between that style and SCA and how the principles and style of SCA might play out in that kind of large scale app.
Furthermore I strongly believe that we shouldn’t store unnecessary states in a reference type store. It is against SwiftUI framework. Such as keeping String bindings for TextField in store class. If I fire search action after completing typing then I shouldn’t keep its state in a reference type but also not keep its state in a property that is all accessible inside view, architecture should provide a proper API similar to current syntax just without storing it.