Hello all,
I'm looking for a correct way of integrating Helm with TCA. I'm the dev of the former and a couple of people asked if this can be done. I've personally never used TCA, still, I'd like to give an idiomatic answer.
Here's what I have so far:
- Add present and dismiss actions:
enum AppAction: Equatable {
//...
case present(fragment: AppFragment)
case dismiss(fragment: AppFragment)
}
- The state should hold the presented fragments:
struct AppState: Equatable {
//...
var presentedFragments: Set<AppFragment>
}
- Keep Helm in the environment:
struct AppEnvironment {
//...
var helm: Helm = Helm(...)
}
- In the reducer, update Helm and the state:
let appReducer = Reducer<AppState, AppAction, AppEnvironment> { state, action, environment in
switch action {
case let .present(fragment):
environment.helm.present(fragment: fragment)
state.presentedFragments = helm.presentedFragments
return .none
case let .dismiss(fragment):
environment.helm.dismiss(fragment: fragment)
state.presentedFragments = helm.presentedFragments
return .none
}
}
- Use TCA in the View as you'd normally do:
.sheet(isPresented: viewStore.binding(
get: { $0.presentedFragments.contains(.welcomeAlert) },
send: .dismiss(fragment: .welcomeAlert)))
Now, one thing still bothers me:
Helm has a couple of helper methods that seamlessly integrate with SwiftUI, mainly isPresented(fragment:)
for Bool
bindings and pickPresented(fragments:)
for TabView
:
.sheet(isPresented: helm.isPresented(.welcomeAlert)) {}
TabView(selection: helm.pickPresented([.library, .news, .settings])) {}
These are convenient and keep the view in the dark. Is there a way to return these bindings instead of the ones above (using viewStore.binding()
)? Also, if not, is there a better way to search if a fragment is visible or not without forcing the view to look for it in a set (i.e. expose a direct method to the view). It's a small thing, but trying to keep the view as stupid as possible.
Also, if I'd have to report an error, I suppose storing it in the state would be the way to go?
Finally, is this an idiomatic integration for TCA. Can I use it as an example in my docs, etc?