Hey @mbrandonw ,
maybe I wasn't clear enough about what I want to achieve but your solution is bascially what I did in the first place. But In this case the parent-reducer receives all possible child actions. I want the parent to receive a mapped version of what the childrens are doing. The Idea behind this, is that I have a wrapper view that can hold multiple child views with different actions and I don't want the parent of this view to receive the specific action of every possible subview that could be displayed by this view. If I would follow your guidance I would need to add multiple child states to the ParentState and multiple childActions to the ParentAction.
If you follow this code example you maybe understand what my issue is.
I am currently not sure if this somehow is against the main idea of TCA.
But for me it feels wrong that every tiny action of every view will be received by the root parent.
The code should compile ;). Thx in advance for your help.
//MARK: Parent
struct ParentState: Equatable {
var wrapperViewState: WrapperViewState
}
enum ParentAction {
case wrapper(WrapperViewAction)
}
struct ParentEnvironment {}
struct ParentView: View {
let store: Store<ParentState, ParentAction>
var body: some View {
WithViewStore(self.store) { viewStore in
WrapperView(store: self.store.scope(state: \.wrapperViewState,
action: ParentAction.wrapper))
}
}
}
let parentReducer: Reducer<ParentState, ParentAction, ParentEnvironment> = .combine (
parentBaseReducer,
wrapperReducer.pullback(
state: \.wrapperViewState,
action: /ParentAction.wrapper,
environment: { _ in .init() }
)
)
let parentBaseReducer = Reducer<ParentState, ParentAction, ParentEnvironment> { state, action, env in
switch action {
case let .wrapper(childAction):
// The Parent knows everything about the specifics of the child views actions
// My goal is to combine A and B and put an abstraction above childViewActionA and childViewActionB
switch childAction {
case .childViewActionA:
return .none
case .childViewActionB:
return .none
}
// The Parent should not know anything about the implementation of the Child Views actions
// It should receive a filtered and adapted version of what happened inside the Wrapper.
// Something like this:
// case let .wrapper(childAction):
// switch childAction {
// case .mappedAction:
// return .none
// }
}
}
//MARK: Wrapper
struct WrapperViewState: Equatable {
var childStateA: AChildViewState
var childStateB: BChildViewState
}
enum WrapperViewAction {
case childViewActionA(AChildViewAction)
case childViewActionB(BChildViewAction)
}
struct WrapperViewEnvironment {}
struct WrapperView: View {
let store: Store<WrapperViewState, WrapperViewAction>
var body: some View {
VStack {
AChildView(store: store.scope(state: \.childStateA,
action: WrapperViewAction.childViewActionA))
BChildView(store: store.scope(state: \.childStateB,
action: WrapperViewAction.childViewActionB))
}
}
}
let wrapperReducer: Reducer<WrapperViewState, WrapperViewAction, WrapperViewEnvironment> = .combine (
achildReducer.pullback(
state: \.childStateA,
action: /WrapperViewAction.childViewActionA,
environment: { _ in .init() }
),
bchildReducer.pullback(
state: \.childStateB,
action: /WrapperViewAction.childViewActionB,
environment: { _ in .init() }
),
wrapperBaseReducer
)
let wrapperBaseReducer = Reducer<WrapperViewState, WrapperViewAction, WrapperViewEnvironment> { state, action, env in
switch action {
case .childViewActionA:
return .none
case .childViewActionB:
return .none
}
}
//MARK: Childs A & B
struct AChildViewState: Equatable {}
enum AChildViewAction {
case aAction
}
struct AChildViewEnvironment {}
struct AChildView: View {
let store: Store<AChildViewState, AChildViewAction>
var body: some View {
WithViewStore(self.store) { viewStore in
Button(action: { viewStore.send(.aAction)}, label: { Text("Send action A") })
}
}
}
let achildReducer = Reducer<AChildViewState, AChildViewAction, AChildViewEnvironment> { state, action, env in
switch action {
case .aAction:
return .none
}
}
struct BChildViewState: Equatable {}
enum BChildViewAction {
case bAction
}
struct BChildViewEnvironment {}
struct BChildView: View {
let store: Store<BChildViewState, BChildViewAction>
var body: some View {
WithViewStore(self.store) { viewStore in
Button(action: {
viewStore.send(.bAction)
}, label: { Text("Send action B") })
}
}
}
let bchildReducer = Reducer<BChildViewState, BChildViewAction, BChildViewEnvironment> { state, action, env in
switch action {
case .bAction:
return .none
}
}