I am trying to understand how SwiftUI works with the Swift TCA - The Composable Architecture.
I'm stuck trying to understand how I can use sub-reducers from the main app reducer. Here is what I have written so far:
import ComposableArchitecture
@Reducer
struct AppReducer {
struct State: Equatable {
var parentState = ParentReducer.State()
var childState = ChildReducer.State()
}
enum Action {
case parent(ParentReducer.Action)
case child(ChildReducer.Action)
}
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .child(let childAction):
state.childState = // how to use child reducer here?
case .parent(let parentAction):
state.parentState = // how to use parent reducer here?
}
return .none
}
}
}
@Reducer
struct ParentReducer {
struct State: Equatable {
var count: Int = 0
}
enum Action {
case increment
}
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .increment:
state.count += 1
return .none
}
}
}
}
@Reducer
struct ChildReducer {
struct State: Equatable {
var count: Int = 0
}
enum Action {
case increment
}
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .increment:
state.count += 1
return .none
}
}
}
}
@main
struct TestTCAApp: App {
let store = StoreOf<AppReducer>(
initialState: AppReducer.State()
) {
AppReducer()
}
var body: some Scene {
WindowGroup {
ParentView(store: store)
}
}
}
struct ParentView: View {
let store: StoreOf<AppReducer>
var body: some View {
WithViewStore(store, observe: { $0.parentState }) { viewStore in
VStack(spacing: 16.0) {
Text("\(viewStore.count)")
Button {
viewStore.send(.parent(.increment))
} label: {
Text("INCREMENT")
.font(.largeTitle)
}
ChildView(store: store)
}
}
}
}
struct ChildView: View {
let store: StoreOf<AppReducer>
var body: some View {
WithViewStore(store, observe: { $0.childState }) { viewStore in
VStack(spacing: 16.0) {
Text("\(viewStore.count)")
Button {
viewStore.send(.child(.increment))
} label: {
Text("INCREMENT")
.font(.largeTitle)
}
}
}
}
}
Can you please help me? I have no idea what to do with child and parent reducers. Thank you.
Although there are multiple methods, TCA recommends handling the child inside the parent.
So in the parent, you will have a
state
,action
, andreducer
for the child (think of it as some proxy):Also, you should scope the parent store for the child store and pass it instead:
The case studies examples are a good place to take a look at different scenarios.
⚠️ Be aware that I code this without the compiler and the code may not be ready to just a simple copy-paste