You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When drilling down in a tree based navigation at least 2 times and then using dismiss() from reducer, it should pop the current screen from the NavigationStack.
When drilling down in a tree based navigation at least 2 times and then using dismiss() from reducer, it empties the view of latest screen. After using native Navigation bar back button from this state, it pops the screen, but the previous one is unresponsive. Only after popping again using native navigation bar it starts working properly again.
Reproducing project
Here's the code used in the recordings:
import ComposableArchitecture
import SwiftUI
@main
struct TestApp: App {
var body: some Scene {
WithPerceptionTracking {
WindowGroup {
NavigationStack {
TreeNavigationView(store: .init(initialState: .init(), reducer: {
TreeNavigation()
}))
}
}
}
}
}
struct TreeNavigationView: View {
@Perception.Bindable var store: StoreOf<TreeNavigation>
var body: some View {
WithPerceptionTracking {
Form {
Button("Show nested") { store.send(.showNested) }
Button("Dismiss") { store.send(.dismiss) }
}
.navigationDestination(item: $store.scope(state: \.destination?.nested, action: \.destination.nested)) { store in
WithPerceptionTracking {
TreeNavigationView(store: store)
}
}
}
}
}
@Reducer
struct TreeNavigation {
@Dependency(\.dismiss) var dismiss
@Reducer(state: .equatable)
enum Destination {
case nested(TreeNavigation)
}
@ObservableState
struct State: Equatable {
@Presents var destination: Destination.State?
}
enum Action {
case destination(PresentationAction<Destination.Action>)
case showNested
case dismiss
}
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .showNested:
state.destination = .nested(.init())
// Alternative approach using parent to nil its destination
// case .destination(.presented(.nested(.dismiss))):
// state.destination = nil
// case .dismiss:
// break
case .dismiss:
return .run { _ in await dismiss() }
case .destination:
break
}
return .none
}
.ifLet(\.$destination, action: \.destination)
}
}
Available also in form of a complete mini project: NavTest.zip
The Composable Architecture version information
1.17.1
Destination operating system
iOS 16.X
Xcode version information
Version 15.4 (15F31d)
Swift Compiler version information
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0
The text was updated successfully, but these errors were encountered:
Neckk
added
the
bug
Something isn't working due to a bug in the library.
label
Feb 11, 2025
Thanks for providing so much info :) I have a feeling this is due to an underlying SwiftUI issue. You can reproduce something similar in vanilla SwiftUI with the following:
There were a few navigation improvements that came with iOS 16.4 which I believe resolved the above issue. This seems to be the case with your demo project as well.
Are you able check iOS 16.4 to see if the issue is still there?
Description
Hey 👋
I have an issue with dismissing screens from reducers on iOS 16.
I use a tree based navigation in my project. The problem happens only on iOS 16.X and only when I drill down at least 2 times. I tried 2 approaches:
@Dependency(\.dismiss) var dismiss
in the current reducerNeither of them works for me. It looks like the reducer is removed from the navigation tree properly, but then NavigationStack fails to refresh and empties the current screen without pop. Here's a video demonstrating the problem:
https://github.com/user-attachments/assets/5b861536-e179-4184-b36b-b986050f2169
Funnily enough, it works properly if we drill down only once:
https://github.com/user-attachments/assets/2626e88a-0e3c-4dc9-9f9d-a5526c9ca6ce
Checklist
main
branch of this package.Expected behavior
When drilling down in a tree based navigation at least 2 times and then using dismiss() from reducer, it should pop the current screen from the NavigationStack.
Here is a recording of the same code working as expected on iOS 17:
https://github.com/user-attachments/assets/75b5227e-f762-4c10-8ecc-58d09ddf65f8
Actual behavior
When drilling down in a tree based navigation at least 2 times and then using dismiss() from reducer, it empties the view of latest screen. After using native Navigation bar back button from this state, it pops the screen, but the previous one is unresponsive. Only after popping again using native navigation bar it starts working properly again.
Reproducing project
Here's the code used in the recordings:
Available also in form of a complete mini project:
NavTest.zip
The Composable Architecture version information
1.17.1
Destination operating system
iOS 16.X
Xcode version information
Version 15.4 (15F31d)
Swift Compiler version information
The text was updated successfully, but these errors were encountered: