Skip to content

Instantly share code, notes, and snippets.

@bsrz
Last active June 1, 2024 16:24
Show Gist options
  • Select an option

  • Save bsrz/aef182114f16d7f75fceb0b3db2c3906 to your computer and use it in GitHub Desktop.

Select an option

Save bsrz/aef182114f16d7f75fceb0b3db2c3906 to your computer and use it in GitHub Desktop.
TCA NavigationStack Example
import ComposableArchitecture
import SwiftUI
@Reducer
public struct ItemListReducer {
@ObservableState
public struct State: Equatable { }
public enum Action: Equatable {
case itemButtonTapped
}
public init() { }
public var body: some ReducerOf<Self> {
Reduce { state, action in
return .none
}
}
}
public struct ItemListView: View {
let store: StoreOf<ItemListReducer>
public init(store: StoreOf<ItemListReducer>) {
self.store = store
}
public var body: some View {
List {
NavigationLink(state: ItemTabReducer.Path.State.item(ItemReducer.State())) {
Label("Go To Item", systemImage: "swift")
}
Text("bar")
Text("qux")
}
}
}
#Preview {
NavigationStack {
ItemListView(
store: Store(
initialState: ItemListReducer.State(),
reducer: { ItemListReducer() }
)
)
}
}
import ComposableArchitecture
import SwiftUI
@Reducer
public struct ItemTabReducer {
@Reducer(state: .equatable, action: .equatable)
public enum Path {
case itemList(ItemListReducer)
case item(ItemReducer)
}
@ObservableState
public struct State: Equatable {
public var path = StackState<Path.State>()
public var itemList = ItemListReducer.State()
}
public enum Action: Equatable {
case path(StackAction<Path.State, Path.Action>)
case itemList(ItemListReducer.Action)
}
public init() { }
public var body: some ReducerOf<Self> {
Scope(state: \.itemList, action: \.itemList, child: { ItemListReducer() })
Reduce { state, action in
switch action {
case .itemList(.itemButtonTapped):
state.path.append(.item(ItemReducer.State()))
return .none
case .path(.element(id: _, action: .itemList(.itemButtonTapped))):
state.path.append(.item(ItemReducer.State()))
return .none
case .path(.element(id: _, action: .item(.listButtonTapped))):
state.path.append(.itemList(ItemListReducer.State()))
return .none
case .path:
return .none
}
}
.forEach(\.path, action: \.path)
}
}
public struct ItemTabView: View {
@Bindable var store: StoreOf<ItemTabReducer>
public init(store: StoreOf<ItemTabReducer>) {
self.store = store
}
public var body: some View {
NavigationStack(path: $store.scope(state: \.path, action: \.path)) {
ItemListView(store: store.scope(state: \.itemList, action: \.itemList))
} destination: { store in
switch store.case {
case .itemList(let store):
ItemListView(store: store)
case .item(let store):
ItemView(store: store)
}
}
}
}
#Preview {
ItemTabView(
store: Store(
initialState: ItemTabReducer.State(),
reducer: { ItemTabReducer() }
)
)
}
import ComposableArchitecture
import SwiftUI
@Reducer
public struct ItemReducer {
@ObservableState
public struct State: Equatable { }
public enum Action: Equatable {
case listButtonTapped
}
public init() { }
public var body: some ReducerOf<Self> {
Reduce { state, action in
return .none
}
}
}
struct ItemView: View {
let store: StoreOf<ItemReducer>
var body: some View {
Button("Go To List") {
store.send(.listButtonTapped)
}
.buttonStyle(.borderless)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment