Skip to content

Instantly share code, notes, and snippets.

@DandyLyons
Created July 11, 2024 19:29
Show Gist options
  • Select an option

  • Save DandyLyons/9d14291284a12939504fc653122167e5 to your computer and use it in GitHub Desktop.

Select an option

Save DandyLyons/9d14291284a12939504fc653122167e5 to your computer and use it in GitHub Desktop.
Tree-Based Push onto NavigationStack using TCA
import SwiftUI
@main
struct TreeBasedPushApp: App {
var body: some Scene {
WindowGroup {
TreeBasedPush_V()
}
}
}
import ComposableArchitecture
@Reducer struct TreeBasedPush_R {
@Reducer enum Destination {
case child1(Child1_R)
case child2(Child2_R)
}
@ObservableState struct State {
@Presents var destination: Destination.State?
}
enum Action {
case destination(PresentationAction<Destination.Action>)
case present(Destination.State)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .destination: return .none
case let .present(destState):
state.destination = destState
return .none
}
}
.ifLet(\.$destination, action: \.destination)
}
}
struct TreeBasedPush_V: View {
@Bindable var store: StoreOf<TreeBasedPush_R> = .init(
initialState: .init(),
reducer: { TreeBasedPush_R()._printChanges() }
)
var body: some View {
NavigationStack {
List {
Button("Child 1") { store.send(.present(.child1(.init())))}
Button("Child 2") { store.send(.present(.child2(.init())))}
}
.navigationTitle("root")
.navigationDestination(
item: $store.scope(state: \.destination?.child1, action: \.destination.child1)
) { store in
Child1_V(store: store)
}
.navigationDestination(
item: $store.scope(state: \.destination?.child2, action: \.destination.child2)
) { store in
Child2_V(store: store)
}
}
}
}
@Reducer struct Child1_R {
@Reducer enum Destination {
case child1(Child1_R)
case child2(Child2_R)
}
@ObservableState struct State {
@Presents var destination: Destination.State?
}
enum Action {
case destination(PresentationAction<Destination.Action>)
case present(Destination.State)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .destination: return .none
case let .present(destState):
state.destination = destState
return .none
}
}
.ifLet(\.$destination, action: \.destination)
}
}
struct Child1_V: View {
@Bindable var store: StoreOf<Child1_R> = .init(
initialState: .init(),
reducer: { Child1_R() }
)
var body: some View {
List {
Button("Child 1") { store.send(.present(.child1(.init())))}
Button("Child 2") { store.send(.present(.child2(.init())))}
}
.navigationTitle("Child 1")
.navigationDestination(
item: $store.scope(state: \.destination?.child1, action: \.destination.child1)
) { store in
Child1_V(store: store)
}
.navigationDestination(
item: $store.scope(state: \.destination?.child2, action: \.destination.child2)
) { store in
Child2_V(store: store)
}
}
}
@Reducer struct Child2_R {
@Reducer enum Destination {
case child1(Child1_R)
case child2(Child2_R)
}
@ObservableState struct State {
@Presents var destination: Destination.State?
}
enum Action {
case destination(PresentationAction<Destination.Action>)
case present(Destination.State)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .destination: return .none
case let .present(destState):
state.destination = destState
return .none
}
}
.ifLet(\.$destination, action: \.destination)
}
}
struct Child2_V: View {
@Bindable var store: StoreOf<Child2_R> = .init(
initialState: .init(),
reducer: { Child2_R() }
)
var body: some View {
List {
Button("Child 1") { store.send(.present(.child1(.init())))}
Button("Child 2") { store.send(.present(.child2(.init())))}
}
.navigationTitle("Child 2")
.navigationDestination(
item: $store.scope(state: \.destination?.child1, action: \.destination.child1)
) { store in
Child1_V(store: store)
}
.navigationDestination(
item: $store.scope(state: \.destination?.child2, action: \.destination.child2)
) { store in
Child2_V(store: store)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment