-
Hi, import ComposableArchitecture
import Foundation
import SwiftUI
// MARK: - First Level
@Reducer
struct FirstLevelFeature {
@ObservableState
struct State: Equatable {
@Presents var destination: Destination.State?
}
enum Action: Equatable {
case destination(PresentationAction<Destination.Action>)
case buttonTapped
case task
case updateDestination
}
var body: some ReducerOf<Self> {
Reduce<State, Action> { state, action in
switch action {
case .task:
return .run { send in
try? await Task.sleep(for: .seconds(10))
await send(.updateDestination)
}
case .updateDestination:
state.destination = .secondLevelB(.init())
return .none
case .buttonTapped:
state.destination = .secondLevelA(.init())
return .none
case .destination:
return .none
}
}
.ifLet(\.$destination, action: \.destination) {
Destination()
}
}
}
extension FirstLevelFeature {
@Reducer
struct Destination {
enum State: Equatable {
case secondLevelA(SecondLevelFeature.State)
case secondLevelB(SecondLevelFeature.State)
}
enum Action: Equatable {
case secondLevelA(SecondLevelFeature.Action)
case secondLevelB(SecondLevelFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: \.secondLevelA, action: \.secondLevelA) {
SecondLevelFeature()
}
Scope(state: \.secondLevelB, action: \.secondLevelB) {
SecondLevelFeature()
}
}
}
}
struct ContentView: View {
@Bindable var store: StoreOf<FirstLevelFeature>
var body: some View {
NavigationStack {
VStack {
Button("Open") {
store.send(.buttonTapped)
}
}
.padding()
.task {
store.send(.task)
}
.navigationDestination(
item: $store.scope(
state: \.destination?.secondLevelA,
action: \.destination.secondLevelA)
) { store in
SecondLevelView(store: store)
}
.navigationDestination(
item: $store.scope(
state: \.destination?.secondLevelB,
action: \.destination.secondLevelB)
) { store in
SecondLevelView(store: store)
}
}
}
}
// MARK: - Second Level
@Reducer
struct SecondLevelFeature {
@ObservableState
struct State: Equatable {
@Presents var destination: Destination.State?
}
enum Action: Equatable {
case destination(PresentationAction<Destination.Action>)
case buttonTapped
}
var body: some ReducerOf<Self> {
Reduce<State, Action> { state, action in
switch action {
case .buttonTapped:
state.destination = .thirdLevel(.init())
return .none
case .destination:
return .none
}
}
.ifLet(\.$destination, action: \.destination) {
Destination()
}
}
}
extension SecondLevelFeature {
@Reducer
struct Destination {
enum State: Equatable {
case thirdLevel(ThirdLevelFeature.State)
}
enum Action: Equatable {
case thirdLevel(ThirdLevelFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: \.thirdLevel, action: \.thirdLevel) {
ThirdLevelFeature()
}
}
}
}
struct SecondLevelView: View {
@Bindable var store: StoreOf<SecondLevelFeature>
var body: some View {
VStack {
Text("Second levle")
Button("Open") {
store.send(.buttonTapped)
}
}
.padding()
.navigationDestination(
item: $store.scope(
state: \.destination?.thirdLevel,
action: \.destination.thirdLevel)
) { store in
ThirdLevelView(store: store)
}
}
}
// MARK: - Third Level
@Reducer
struct ThirdLevelFeature {
@ObservableState
struct State: Equatable {
}
enum Action: Equatable {
}
var body: some ReducerOf<Self> {
Reduce<State, Action> { state, action in
return .none
}
}
}
struct ThirdLevelView: View {
@Bindable var store: StoreOf<ThirdLevelFeature>
var body: some View {
VStack {
Text("Third level")
}
.padding()
}
}
#Preview {
ContentView(
store: Store(initialState: FirstLevelFeature.State()) {
FirstLevelFeature()
})
} Warning:
|
Beta Was this translation helpful? Give feedback.
Answered by
shoplab7
Feb 7, 2024
Replies: 1 comment
-
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
shoplab7
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://pointfreecommunity.slack.com/archives/C04KQQ7NXHV/p1707244403880719?thread_ts=1706700803.236549&cid=C04KQQ7NXHV