NavigationStack with multiple destinations #3239
Replies: 1 comment
-
It sounds like you're using what the docs refer to as stack-based navigation. This is where you have a single path value used by the app's struct RootView: View {
@Bindable var store: StoreOf<Root>
var body: some View {
NavigationStack(path: $store.scope(state: \.path, action: \.path)) {
TopLevelView()
} destination: { pathStore in
switch pathStore.case {
case .screenA(let aStore):
ScreenAView(store: aStore)
...
}
}
}
} Now all you need to do is add state values to that path. How you do that is dependent on how you've designed your app. You could use an in-memory @Reducer
struct Root {
@Reducer
enum Path {
case screenA(ScreenA)
case screenB(ScreenB)
...
}
struct State {
@Shared(.path) var path
}
...
}
@Reducer
struct ScreenA {
struct State {
@Shared(.path) var path
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .buttonTapped:
state.path.append(.screenB(ScreenB.State()))
return .none
...
}
}
}
} Another approach is for child features to declare delegate actions when they want to push a new screen onto the navigation stack. The root module would listen for those delegate actions and push the path values itself. As you say, you'll end up with a pretty big reducer if there's a good deal of navigation in your app. However, it also decouples the child features from each other so they're easily testable. It looks something like this: @Reducer
struct Root {
@Reducer
enum Path {
case screenA(ScreenA)
case screenB(ScreenB)
...
}
struct State {
var path: StackState<Path.State>
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .screenA(.delegate(.buttonTapped)):
state.path.append(.screenB(ScreenB.State()))
return .none
...
}
}
}
} Personally I found the modularity and testability to be important enough to use the second approach, but either way works. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone, I am currently developing an application from scratch and I've decided to go all the way with TCA. Although I really love the library, I am reaching an issue with navigation and I don't know how to proceed. The scenario is the following:
Imagine that I have a MainScreen, this screen shows two tabs (TabA, and TabB). What I want to achieve is to be able to navigate to different screens (ScreenA, ScreenB, ScreenC) from the different tabs. For that I thought of using MainScreen's Path with both TabA and TabB. This way, I thought I would be able to navigate from both Tabs but that is not the case because the Path is not correctly set. So, my question is, is there a way to share MainScreen's Path? I want to avoid having a huge Reducer in the MainScreen that handles all the navigations in the application.
I could share some code to explain myself better as soon as I get home.
Thank you all in advance.
Beta Was this translation helpful? Give feedback.
All reactions