Managing NavigationView/Stack/Flow in TCA #429
Replies: 4 comments 6 replies
-
I was wondering about the same thing some time ago. Sadly SwiftUI doesn't allow for such fine grained control yet. If you try adding all navigation links in a view only the one of them will be rendered and the navigation view will break if you try to enable another one. Hopefully in a next version of SwiftUI we will get better support for such cases. In the meantime we can probably use UIKit for that |
Beta Was this translation helpful? Give feedback.
-
The approach I've taken so far is to pass the full Questions state along to each screen, and scope down using WithViewStore. |
Beta Was this translation helpful? Give feedback.
-
I don't have an ultimate answer on this question, but I think I have a lead. I created a struct RouterView: View {
private let scene: ScreenScene
private let store: Store<State, Action>
init(scene: ScreenScene, store: Store<State, Action>) {
self.scene = scene
self.store = store
}
var body: some View {
WithViewStore(store.scope(state: \.scenesStack)) { viewStore in
HStack {
scene(for: scene, send: viewStore.send)
NavigationLink(
destination: nextScene(for: scene),
isActive: viewStore.binding { $0.contains(scene.next) },
label: EmptyView.init
)
}
.navigationBarHidden(true)
}
}
}
// MARK: - View Factory
private extension RouterView {
@ViewBuilder
func scene(for type: ScreenScene, send: @escaping (Action) -> Void) -> some View {
switch type {
case .loadingWords:
LaunchView(send: send)
case .privateTeacher:
OnboardingView(
title: L10n.Onboarding.PrivateTeacher.title,
image: Asset.lesson,
buttonTitle: L10n.Onboarding.PrivateTeacher.buttonTitle,
action: { send(.goNext(from: type)) }
)
case .wantToLearn:
OnboardingView(
title: L10n.Onboarding.WantToLearn.title,
image: Asset.classLessons,
buttonTitle: L10n.Onboarding.WantToLearn.buttonTitle,
action: { send(.goNext(from: type)) }
)
case .oldMethods:
OnboardingView(
title: L10n.Onboarding.OldMethods.title,
image: Asset.oldMethods,
buttonTitle: L10n.Onboarding.OldMethods.buttonTitle,
action: { send(.goNext(from: type)) }
)
case .addWords:
OnboardingView(
title: L10n.Onboarding.AddWords.title,
image: Asset.dictionary,
buttonTitle: L10n.Onboarding.AddWords.buttonTitle,
action: { send(.goNext(from: type)) }
)
case .dictionary:
DictionaryView(store: store.scope(state: \.dictionary, action: Action.dictionary))
}
}
@ViewBuilder
func nextScene(for type: ScreenScene) -> some View {
RouterView(
scene: type.next,
store: store
)
}
} |
Beta Was this translation helpful? Give feedback.
-
I found https://github.com/Bahn-X/swift-composable-navigator interesting, maybe this can be an inspiration. It does not work on macOS atm though. |
Beta Was this translation helpful? Give feedback.
-
How are you all managing navigation stacks in the TCA? Manually linking views in the standard way (i.e. NavigationLinks to a particular view), or is there a clean TCA way to manage the flow of views, handle Back, etc, using actions and state?
Ideally I would like every view to be entirely independent, not even knowing what came before or after it. But I can't work out a nice way (If I've missed an example or video please just point me in the right direction. 🙂)
The style of flow I'm a stumped on is a questionnaire where each screen is focused on it's own subset of the full list of questions, but each screen isn't focusing down on the last, it's "parallel" if you like. e.g.:
IntroView
->QuestionAView
->QuestionBView
->InfoView
->QuestionCView
Would you simply pass the entire
Questions
state along to every view in the chain, even though some don't use state at all, and each only really needs to know about it's own single question?Beta Was this translation helpful? Give feedback.
All reactions