Sample code for the question below can be found at: GitHub - CSCIX65G/TCAExample
I have a pair of states and actions that look like this:
// Top Level State
public struct AppState: Equatable {
var selectedRow: Int? = .none
var title: String = ""
var navigations: [NavState] = ["Nav 1", "Nav 2", "Nav 3"]
.enumerated()
.map(NavState.init)
}
public extension AppState {
enum Action: Equatable {
case setSelectedRow(Int?)
case navigationAction(index: Int, action: NavState.Action)
}
}
// ForEachStore'd State
public struct NavState: Equatable {
var index: Int
var title: String
}
extension NavState: Identifiable {
public var id: Int { index }
}
public extension NavState {
enum Action: Equatable {
case setTitle(String)
case setSelectedRow(Int?)
}
}
The lower level state has an action which can affect the upper level state. The lower state is displayed by nesting in a ForEachStore.
The reducer looks like this:
let reducer = Reducer<AppState, AppState.Action, Environment> { state, action, _ in
switch action {
case .navigationAction(index: _, action: let action):
switch action {
case .setTitle(let title):
state.title = title
case .setSelectedRow(let row):
state.selectedRow = row
}
return .none
case .setSelectedRow:
state.selectedRow = .none
return .none
}
}.debug()
I don't like the switch-within-a-switch look there. I'd like the shape of the reducer to be: Reducer<AppState, NavState.Action, Environment>
and to pull that back in a combine
with a top-level reducer of type Reducer<AppState, AppState.Action, Environment>
, but I can't because the navigationAction takes 2 args rather than 1. Is there something I am missing in CasePaths that would allow me to do such a pullback?
Just a note on this example. I work on an TabView-driven app (not SwiftUI or TCA yet) where one of the tabs is the account page. The user can login/logout/change profile in that tab and it affects global state used by everything else in the app.
We'e been discussing migrating the app and this is one of the places that we don't quite see how to implement yet. What motivated this example is that the user can have navigated down to a page that is two or three scope
calls away from the main AppState with one of the scopes being inside a ForEachStore and we can't figure out how to pullback
that context into the main state.